在我的Capybara + Webdriver AJAX测试中,我看到了这样的代码模式:
page.should have_selector('foo.bar > baz') # added dynamically by JS
visit current_page
page.should have_selector('foo.bar > baz') # still there after reload
我将其解压缩为persist
辅助函数,该函数执行
def persist
yield
visit current_page
yield
end
问题:在没有帮助函数的情况下,是否有一个紧凑的成语来内联相同的东西?
我能想到的最短的是
2.times { |i|
page.should have_selector('foo.bar > baz')
visit current_page if i == 0
}
这是干的,但仍然很难看。
编辑:我认为Mark的评论非常正确,而且我坚持使用persist
帮助器来处理这个特殊用例。也就是说,下面的答案中有几个好的(和有趣的)想法。
编辑2:如果有人想要复制我的persist
示例:使用RSpec,在@__memoized = {}
之后添加visit current_page
以便更新是有用的任何let个持有节点,在页面重新加载后会过时(否则你会得到一个ObsoleteElementError
)。
答案 0 :(得分:5)
在我看来,重复一行是没有错的,如果它使代码更具可读性。您的案例似乎是这种合理重复的一个很好的例子:)
如果你发现自己重复了很多模式,你可能希望用{/ p>这样的方式扩展Object
def should_still(predicate)
should predicate
yield
should predicate
end
然后你可以编写像
这样的紧凑语句page.should_still have_selector('foo.bar > baz') { visit current_page }
答案 1 :(得分:3)
您可以按照http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/1052c289b22c60a5
的模式制作通用版本class AroundWrapper
def initialize &block
(class << self
def self.outer &block
define_method :outer, &block
end
def self.inner &block
define_method :inner, &block
end
self
end).class_eval &block
end
end
def around &block
around_wrapper = AroundWrapper.new &block
around_wrapper.outer
around_wrapper.inner
around_wrapper.outer
end
然后,这个:
around {
outer { puts "Hello" }
inner { puts "World" }
}
将产生此输出:
Hello
World
Hello
编辑:实际上,现在我已经想到了,这里有一个更简单的方法,在使用中读得非常好:
def around(inner)
yield
inner.call
yield
end
around(lambda{puts "World"}) do
puts "Hello"
end
答案 2 :(得分:0)
在这种情况下,我会引导你远离“聪明”的解决方案。测试应该是相当程序化的配方,如果你抽象成像你的例子那样,测试就失去了它的可读性。我可以很容易地理解第一次测试的意图和目的,但“浓缩”版本就像泥浆一样清晰。
在这种情况下,我鼓励您不一定觉得您需要避免代码重复,如果它让您清晰明了。如果您仍想抽象它,我会推荐像帮手一样的东西,比如
after_refresh { page.should have_selector("foo.bar > baz") }
然后,
def after_refresh(&block)
yield
visit current_page
yield
end
这样可以保持测试的富有表现力,如果您正在测试很多这些刷新案例,那么可以避免重复。