Cucumber步骤定义中的实例变量(即什么是self)有什么对象?
我不理解在Ruby中使用Cucumber时的范围,特别是关于实例变量。
对于我的直接示例的上下文,在hooks.rb
的Before部分中, hooks.rb
了变量@browser
。
@browser = Watir::Browser.new @browser_selected.to_sym
(其中@browser_selected
通常是’chrome’)
在步骤定义中使用@browser。 举个简单的例子: @browser.send_keys(:tab)
我不明白的是什么对象包含@browser作为属性。 它在这方面有什么意义? 我知道我困惑的代码总是在一个块中,并且我认识到每个这样的块被使用(通过它附加的Given / When / Then消息)以某种神秘的方式进行预处理。
这种神秘的遮蔽是实例变量的范围。 如何知道这些块中的实例变量的范围?
self
在Cucumber步骤和钩子只是一个Ruby对象,“世界”,在每个场景中使用。 每个步骤定义中的块都在世界的上下文中使用the_world.instance_eval
或类似的东西执行,这意味着当每个块运行时, self
就是世界。 因此,所有这些实例变量所属的对象是同一个对象,即世界。 所有这些实例变量的范围都是整个场景。
因此,在Cucumber步骤中谨慎使用实例变量非常重要,并在步骤名称中明确表示您正在使用它们(也就是说,在步骤名称中明确指出它们指的是某些状态)。 这些步骤清楚地指的是在幕后保存的东西(即引用相同的实例变量):
Given there is a thing When I frob the thing Then the thing should be frobbed
那很好也很正常。 但是如果When I frob the thing
预先计算出一些预期的断言结果并将它们隐藏在实例变量中时,那将是非常可怕的, Then the thing should be frobbed
在其断言中使用那些实例变量。 Then the thing should be frobbed
不会起作用,除非When I frob the thing
把它之前When I frob the thing
了,使它不那么可重复使用,并且这种限制对于其他人写作function并不明显,他们会变得沮丧。 (不要像我以前的同事一样。)
回到世界:Cucumber为每个场景创造了一个新世界,并在最后抛出它,因此场景的实例变量不会影响下一个场景。 在普通的Cucumber中,世界只是Object
一个实例。 在cucumber-rails中,它是Cucumber::Rails::World
的一个实例( 有趣的是阅读 )。 除了在cucumber-rails中为世界构建的方法之外,世界通过扩展模块获得其方法(如在the_world.extend SomeModule
)。 与实例变量一样,来自世界扩展的所有模块的所有方法都被卡在同一个对象(世界)上,因此您有时需要担心名称冲突。