以下代码不起作用,但它最能说明我正在努力实现的目标
context "this context describes the class" do
subject do
# described class is actually a module here
c = Class.new.extend(described_class)
c.some_method_that_has_been_added_through_extension
c
end
# ... testing the class itself here ...
context "instances of this class" do
subject do
# this doesn't work because it introduces a endless recursion bug
# which makes perfectly sense
subject.new
end
end
end
我还尝试在我初始化的内部上下文中使用局部变量 与主题,但没有运气。有没有什么方法可以从内部范围内的主题定义中访问外部范围的主题?
答案 0 :(得分:3)
使用#subject有时会造成麻烦。它主要用于#its等短手检查。
它也可以使示例更难阅读,因为它可以掩盖您测试的名称/意图。以下是David Chelimsky撰写的关于#subject和#let主题的博客文章及其在揭示意图中的作用:http://blog.davidchelimsky.net/blog/2012/05/13/spec-smell-explicit-use-of-subject/
请尝试使用let https://www.relishapp.com/rspec/rspec-core/v/2-10/docs/helper-methods/let-and-let
以下是我最有可能写的内容。
context "this context describes the class" do
let(:name_of_the_module) { Class.new.extend(described_class) }
before do
c.some_method_that_has_been_added_through_extension
end
# ... testing the class itself here ...
context "instances of this class" do
let(:better_name_that_describes_the_instance) { klass.new }
# ... test the instance
end
end
旁注 您可能想要重新审视是否要使用主题。我几乎在所有情况下都喜欢使用#let。 YMMV
答案 1 :(得分:0)
显然有效的方法是在内部上下文中使用实例变量,而不是使用subject
而是subject.call
初始化它。主题是过程。因此,我的第一种方法不起作用。
context "instances of this class" do
klass = subject.call
subject { klass.new }
end
答案 2 :(得分:0)
我一直在寻找解决方案,但出于不同的原因。当我测试一个可能返回值或引发错误的方法时,我经常需要在两个上下文中重复该主题,一次作为raise_error
的proc和一次正常。
我发现您可以提供subjects
名称,例如lets
。这样,您就可以从新subject
中的外部作用域引用已命名的subject
。这是一个例子:
describe 'do_some_math' do
let!(:calculator) { create(:calculator) }
# proc to be used with raise_error
subject(:do_some_math) {
-> { calculator.do_some_math(with, complicated, args) }
}
context 'when something breaks' do
it { is_expected.to raise_error } # ok
end
context 'when everything works' do
# here we call the named subject from the outer scope:
subject { do_some_math.call } # nice and DRY
it { is_expected.to be_a(Numeric) } # also ok!
end
end