我recently asked如何在RSpec中测试是否调用了一个块,并且该问题的答案似乎在一个简单的情况下起作用。问题是当块的初始化更复杂时。然后它在before
中完成,并在上下文中通过许多不同的测试重用,其中一个测试块是否被评估。参见示例:
context "the node definition using block of code" do
before do
@n=node do
# this block should be called
end
# some more complex setup concerning @n
end
it "should call the block" do
# how to test it?
end
# here a bunch of other tests using @n
end
在这种情况下,具有副作用改变局部变量值的解决方案不起作用。从块中引发异常是无用的,因为必须正确评估整个语句以供其他测试使用。
显然我可以单独进行测试,但它似乎很臭,因为我必须复制粘贴初始化部分,因为这个被称为测试的测试本身就属于这个环境。
如何测试是否在这种情况下评估了块?
以下@zetetic提出的问题解释。
上下文是我正在实现一种DSL,其中节点由其参数和代码块定义(可以在节点范围内定义其他内容)。由于节点块定义的内容可能非常通用,至少在第一次尝试时我只需要确保对块进行评估,并考虑用户提供的内容。现在不管它是什么。
可能我现在应该重构我的测试并使用模拟使它们成为测试行为而不是实现。然而,为了一些mixins和动态处理发送给对象的消息,这将有点棘手。现在,这些测试的结果在我脑海中有点模糊; - )
无论如何,你的答案和评论帮助我更好地理解RSpec的工作原理,并解释了为什么我要做的事情看起来好像不适合RSpec。
答案 0 :(得分:1)
尝试这样的事情(我未经测试):
context "the node definition using block of code" do
let(:node){
node = Node.new "arg1", "arg2", node_block
# more complex stuff here
node
}
context "checking the block is called" do
let(:node_block) {
double = double("node_block")
double.should_receive("some kind of arg").and_return("something")
# this will now cause a fail if it isn't called
double
}
it "should call the block" do
node.blah()
end
end
let(:node_block) {
# some real code
}
subject { node.blah() }
it { should == 2 }
# ...
end
所以这是一段非常不稳定的代码(你必须填补空白,因为你没有给予很多的继续,let
显然也是一个lambda,这可能意味着你'我必须使用let
和double
来检查它的调用,并避免使用before
,这实际上是副作用不是设置变量以在规范中使用。
@zetetic做了一个非常有见地的评论,说你不是在这里测试行为。我不反对使用rspec来做更多单元测试样式的东西(指导方针被破坏),但你可能会问,如果没有调用那个块,那么在使用真正的代码块时,测试将如何通过?在某种程度上,我甚至不确定你是否需要检查该块被调用,但只有你知道。