Class 已泄漏到另一个示例中,不能再在规范中使用
Class has leaked into another example and can no longer be used in spec
我无法在本地复制它,但出于某种原因,在 CircleCi 中进行 运行 测试时出现以下错误:
<Double Mylogger> 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.
这是我的代码的简化版本:
# frozen_string_literal: true
describe 'my_rake_task' do
let(:my_log) { Mylogger.new }
subject { Rake::Task['my_rake_task'].execute }
describe 'one' do
context 'logs' do
let(:logs) do
[
['My message one'],
['My message two'],
]
end
after { subject }
it 'correctly' do
logs.each { |log| expect(my_log).to receive(:info).with(*log) }
end
end
end
describe 'two' do
context 'logs' do
let(:logs) do
[
['My message three'],
['My message four'],
]
end
after { subject }
it 'correctly' do
logs.each { |log| expect(my_log).to receive(:info).with(*log) }
end
end
end
end
为什么说MyLogger是一个double?为什么会漏水?
错误说 MyLogger
是双精度的原因是因为它是一个。当您调用 expect(my_log).to receive
或 allow(my_log).to receive
时,您将实例转换为 partial-double.
至于 my_log
泄漏的原因:从您发布的代码无法判断。为了造成泄漏,您的 rake 任务或规范本身中的某些代码需要将 my_log
注入某些全局状态,like a class variable.
大多数情况下,这种事情是由在 class 变量中存储某些内容引起的。您将必须弄清楚它在哪里,以及如何清除它或避免使用 class 变量 - 它可能在您的 class 或 gem.
中
如果可能,使用 class 变量或外部系统导致 inter-test 问题的最佳做法是在测试之间清除此类问题。例如 ActionMailer::Base.deliveries
和 Rails.cache
是应该清除的常见事物。如果您正在使用那些 gem,您还应该清除 Faker::UniqueGenerator
或 RequestStore
,我相信还有更多。
找到 class 变量后,如果它在您的代码中,并且您确定 class 变量是正确的方法,您可以添加 reset
或 clear
class 方法到 class 并在 before(:each)
RSpec 块中调用它 spec_helper.rb
或 rails_helper.rb
.
请注意,虽然很多东西会在测试之间自动清除(例如 RSpec 模拟),并且让您认为这是完全自动的,但实际上它通常不是。
测试将仅通过以下方式保持独立:(a) 主要使用在测试中创建的对象,并且主要只在其中存储数据,以及 (b) 确保在测试之间通过您的显式代码或在负责的 gem.
这在处理外部 third-party 系统时尤其烦人,这些系统很少提供 API 来清理暂存环境,因此即使在使用 vcr
gem.
我无法在本地复制它,但出于某种原因,在 CircleCi 中进行 运行 测试时出现以下错误:
<Double Mylogger> 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.
这是我的代码的简化版本:
# frozen_string_literal: true
describe 'my_rake_task' do
let(:my_log) { Mylogger.new }
subject { Rake::Task['my_rake_task'].execute }
describe 'one' do
context 'logs' do
let(:logs) do
[
['My message one'],
['My message two'],
]
end
after { subject }
it 'correctly' do
logs.each { |log| expect(my_log).to receive(:info).with(*log) }
end
end
end
describe 'two' do
context 'logs' do
let(:logs) do
[
['My message three'],
['My message four'],
]
end
after { subject }
it 'correctly' do
logs.each { |log| expect(my_log).to receive(:info).with(*log) }
end
end
end
end
为什么说MyLogger是一个double?为什么会漏水?
错误说 MyLogger
是双精度的原因是因为它是一个。当您调用 expect(my_log).to receive
或 allow(my_log).to receive
时,您将实例转换为 partial-double.
至于 my_log
泄漏的原因:从您发布的代码无法判断。为了造成泄漏,您的 rake 任务或规范本身中的某些代码需要将 my_log
注入某些全局状态,like a class variable.
大多数情况下,这种事情是由在 class 变量中存储某些内容引起的。您将必须弄清楚它在哪里,以及如何清除它或避免使用 class 变量 - 它可能在您的 class 或 gem.
中如果可能,使用 class 变量或外部系统导致 inter-test 问题的最佳做法是在测试之间清除此类问题。例如 ActionMailer::Base.deliveries
和 Rails.cache
是应该清除的常见事物。如果您正在使用那些 gem,您还应该清除 Faker::UniqueGenerator
或 RequestStore
,我相信还有更多。
找到 class 变量后,如果它在您的代码中,并且您确定 class 变量是正确的方法,您可以添加 reset
或 clear
class 方法到 class 并在 before(:each)
RSpec 块中调用它 spec_helper.rb
或 rails_helper.rb
.
请注意,虽然很多东西会在测试之间自动清除(例如 RSpec 模拟),并且让您认为这是完全自动的,但实际上它通常不是。
测试将仅通过以下方式保持独立:(a) 主要使用在测试中创建的对象,并且主要只在其中存储数据,以及 (b) 确保在测试之间通过您的显式代码或在负责的 gem.
这在处理外部 third-party 系统时尤其烦人,这些系统很少提供 API 来清理暂存环境,因此即使在使用 vcr
gem.