由于外部库不公开接口(interface)(因此不可模拟)而只公开纯函数,因此我很难用 Go 编写单元测试。甚至像Google don't这样的大公司,所以我想知道我的方法是否足够好。
库提供 interface 而不是只有功能的包以便让用户模拟它们不是很好的做法吗?
到目前为止,我提出的解决方案是用接口(interface)的实现来包装这些包,但这看起来工作量太大。
我举个例子。我的函数看起来像这样
func AnyFunction() error {
sess := session.Get("blabla")
// logic in here...
}
其中 session 是一个导入的包,它返回一个 struct。我无法模拟包 session。
对于这种情况,我将编写一个带有实现的 SessionInterface,它在内部调用 session 。
例如:
type SessionInterface interface {
Get(s string) Session
}
type mySessionImpl struct {}
func (me *mySessionImpl) Get(s string) Session {
return session.Get(s)
}
对于我的测试,现在我可以模拟 SessionInterface 并将其注入(inject)到我的代码中
最佳答案
你在这里做的是对的,这是语言设计者的一个有意识的决定。
Go 的哲学是你的代码应该“拥有”那些接口(interface),而不是库。在 C# 和 Java 等语言中,库会预先定义它们的接口(interface),而无需真正了解消费者的实际需求。 (也许它们包括太多方法,或者太少。)在 Go 中,因为消费者有效地“拥有”接口(interface),你有权指定哪些方法实际需要出现在最小接口(interface)中,以及程序需求的变化这意味着您还可以更改界面。
现在在这种特殊情况下,为了可测试性而在函数前面创建适配器似乎很奇怪,但请考虑替代方案:如果 session.Get() 是接口(interface)或结构的方法,而不是函数,它将强制所有库使用者实例化一个虚拟对象以调用该方法。不是每个人都会伪造它——他们更容易说想要的消费者(比如你)有权编写适配器,而那些不想的消费者可以幸福地忽略它们。
关于unit-testing - Golang 接口(interface)和模拟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55105509/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定
我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho
在Test::Unit中的ruby单元测试断言失败后,在执行teardown之前,是否有一些简洁优雅的方法来立即执行我的代码?我正在做一些自动化的GUI测试,并希望在出现问题后立即截图。 最佳答案 如果您使用的是1.9,请不要使用Test::Unit::TestCase作为您的基类。对其进行子类化并覆盖#run_test以进行救援,截取屏幕截图并重新提出:classMyAbstractTestCase或者,我认为这实际上是最简洁的方法,您可以使用before_teardownHook:classMyTestCase这不适用于1.
我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat
我正在尝试测试命令行工具的输出。如何使用rspec来“伪造”命令行调用?执行以下操作不起作用:it"shouldcallthecommandlineandreturn'text'"do@p=Pig.new@p.should_receive(:run).with('my_command_line_tool_call').and_return('resulttext')end如何创建stub? 最佳答案 使用newmessageexpectationsyntax:规范/虚拟规范.rbrequire"dummy"describeDummy
显然在Test::Unit中没有assert_false。您将如何通过扩展断言并添加文件config/initializers/assertions_helper.rb来添加它?这是最好的方法吗?我不想修改test/unit/assertions.rb。顺便说一句,我不认为这是多余的。我使用的是assert_equalfalse,something_to_evaluate。这种方法的问题是很容易意外使用assertfalse,something_to_evaluate。这将始终失败,不会引发错误或警告,并且会在测试中引入错误。 最佳答案