dav*_*ris 11 ruby unit-testing rspec ruby-on-rails rspec-mocks
我有一个关于如何在示例之间分享rspec-mocks的双重问题.我正在用rspec-mocks编写一个新的rails应用程序3.1.3
.我习惯使用旧的(<2.14并尝试更新我的知识,如果当前的rspec使用.
我有一个模型方法:
def self.from_strava(activity_id, race_id, user)
@client ||= Strava::Api::V3::Client.new(access_token: 'abc123')
activity = @client.retrieve_an_activity(activity_id)
result_details = {race_id: race_id, user: user}
result_details[:duration] = activity['moving_time']
result_details[:date] = Date.parse(activity['start_date'])
result_details[:comment] = activity['description']
result_details[:strava_url] = "http://www.strava.com/activities/#{activity_id}"
Result.create!(result_details)
end
Run Code Online (Sandbox Code Playgroud)
以下是规范:
describe ".from_strava" do
let(:user) { FactoryGirl.build(:user) }
let(:client) { double(:client) }
let(:json_response) { JSON.parse(File.read('spec/support/strava_response.json')) }
before(:each) do
allow(Strava::Api::V3::Client).to receive(:new) { client }
allow(client).to receive(:retrieve_an_activity) { json_response }
allow(Result).to receive(:create!)
end
it "sets the duration" do
expect(Result).to receive(:create!).with(hash_including(duration: 3635))
Result.from_strava('123', 456, user)
end
it "sets the date" do
expect(Result).to receive(:create!).with(hash_including(date: Date.parse("2014-11-14")))
Result.from_strava('123', 456, user)
end
end
Run Code Online (Sandbox Code Playgroud)
当我自己运行单个测试时它很好,但是当我运行整个describe ".from_strava"
块时它会失败并显示消息
Double :client was originally created in one example but has leaked into another example and can no longer be used. rspec-mocks' doubles are designed to only last for one example, and you need to create a new one in each example you wish to use it for.
Run Code Online (Sandbox Code Playgroud)
我理解它的含义,但肯定这是double
在2个例子中使用的适当用法.毕竟,client
double对示例来说并不重要,它只是我加载预设响应的一种方式.我想我可以使用WebMock,但这似乎非常低级,并且不能很好地转换为实际编写的代码.毕竟,我们应该只为每个例子断言一件事.
我曾考虑过用client
一个电话取代双人
allow(Strava::Api::V3::Client).to receive_message_chain(:new, :retrieve_an_activity) { json_response }
Run Code Online (Sandbox Code Playgroud)
但这似乎也不是正确的方法,因为文档说明 receive_message_chain
应该是代码气味.
所以,如果我不使用receive_message_chain
,共享client
双重并遵循标准DRY原则那么我应该如何解决这个问题呢?
我会喜欢这方面的一些反馈.
谢谢,戴夫
当然,这是在两个例子中使用的双重的适当使用.
不,这不对.:)你正在尝试使用类变量; 不这样做,因为变量不跨越示例.解决方案是每次设置客户端,即在每个示例中.
坏:
@client ||= Strava::Api::V3::Client.new(access_token: 'abc123')
Run Code Online (Sandbox Code Playgroud)
好:
@client = Strava::Api::V3::Client.new(access_token: 'abc123')
Run Code Online (Sandbox Code Playgroud)
我不喜欢这个答案。通常经常需要为外部组件缓存客户端(保持活动连接/您可能需要的任何SSL设置,等等),并且为了解决测试问题而删除它不是理想的解决方案。
为了修复您的测试(无需重构代码),您可以执行以下操作在每个测试之后清除实例变量:
after { Result.instance_variable_set("@client", nil) }
Run Code Online (Sandbox Code Playgroud)
公认的是,这不是最干净的解决方案,它似乎是最简单的解决方案,并且可以同时实现这两种解决方案,它使您可以进行清晰的设置,并且测试之间没有共享状态,并使客户端缓存在“正常”操作模式下。