为使用类的gem编写单元测试的最佳方法是什么?我已经编写了一个宝石,可以在初始化过程中完成包含外部集成的工作。在编写测试时,我不想初始化所有内容,我只是想测试某些功能。
例如,我有lib/foomon.rb
:
class FooMon
def initialize
@log = Logger.new("app.log","daily")
pollingClient = SomePoller.new(remote_service_url)
pollingClient.poll do |response|
processResponse(response)
end
end
private
def processResponse(res)
{:response => res.body}
end
end
现在我想测试processResponse
功能。我采取的方法是删除private
修饰符,然后将代码从initialize
移动到新的setup
方法。应用程序的主要入口点然后调用设置,但我的测试不是(他们在@foomon = FooMon.new
中只有before
)。然后规范可以测试@foomon.processResponse
这是最好的方法吗?
答案 0 :(得分:1)
过去我做过这个时,我倾向于使用RSpec Mocks (doubles)。在你的特定情况下,我认为,存在#body
的双精度可以解决问题。
RSpec.describe FooMon do
before do
@foomon = FooMon.new
end
it "should process the response" do
response = instance_double("Response")
expect(response).to receive(:body).once.and_return("I ain't got no body ...")
expect {response_body = @foomon.send(:process_response, response)}.not_to raise_error
expect response_body == "I ain't got no body ..."
end
end
免责声明:使用老化的内存在浏览器中编写。可能需要调试。
这是我能抓住的最好的real-life, working example。希望这有助于提供一些颜色。
答案 1 :(得分:1)
规范应该只测试公共方法,如果你实际删除了这个类的私有修饰符processResponce
可以测试,否则没有什么可以在那里测试。
关于班级的外部整合,在单元测试方法中,你应该只测试班级本身的回报。
在这种情况下,您应该只测试从processResponce
返回的内容,其他类(如Logger
和SomePoller
生成的所有逻辑都应该在其他规范上进行测试,而不是这个。
在这种情况下,我建议更改初始化程序中的逻辑并将其移动到单独的公共方法。因此,该方法可以负责将消息发送给客户端,并且更容易测试。
您可以使用double
模拟这些类的行为。像这样:
let(:poller) { double(:poller)
let(:responce) { double(:responce, body: "message") }
before do
allow(poller).to receive(:poll).and_yield(responce)
allow(SomePoller).to response(:new) { poller }
end
it 'send a message to the client' do
expect(response).to receive(:body).once
subject.send_client
end
有了这个,你只能测试班级职责,并且说明你的考试太复杂了。
参考文献:
https://www.relishapp.com/rspec/rspec-mocks/v/3-6/docs/ https://relishapp.com/rspec/rspec-mocks/docs/configuring-responses/yielding#yield-an-argument