有没有一种方法可以在每个带有特定标签的黄瓜功能之前和之后运行特定的代码块?
由于设置过程非常昂贵,我不想在每个场景之前都运行它。
LukasMac的回答不适用于@variable。Ande基于官方的cucumber wiki页面,我下面的例子运行良好,测试正常,下面的前挂钩每个功能只执行一次:
Before('@my_feature_tag') do
unless $dts_test_preparation_done
# expensive setup in my case setup lots of database tables for test
$dts_test_preparation_done = true
end
end
几天前,我与Matt Wynne(cucumber gem的核心团队成员之一)进行了交谈,他告诉我cucumber中没有这样的功能(在撰写本文时)。
作为一种变通方法,他建议标记整个功能,并在每个挂钩之前使用这样的标志:
Before('@feature_with_expensive_setup') do
unless @setup_is_done
# perform expensive setup code here ..
@setup_is_done = true
end
end
黄瓜的钩子在这个wiki页面中进行了描述,它显示了您可以使用的前后钩子。
这个页面上的例子是:
如果执行时间超过0.5秒,以下示例将导致标记为@fast的场景失败:
Around('@fast') do |scenario, block|
Timeout.timeout(0.5) do
block.call
end
end
特性挂钩前后的Cucumber
使用情况信息
由于ruby cucumber没有提供为特性前后创建挂钩的选项,因此提出了一个特别的解决方案。
为了指定与功能相关的挂钩,方法名称必须采用以下格式:
before_feature_[格式化的功能名称]after_feature_[格式化的功能名称]
其中格式化的功能名称是使用格式化的功能文件中"功能:"行中的文本
(i) 所有字符都小写;(ii)所有用下划线取代的空格;和(iii)删除的所有特殊字符
在与此约定匹配的方法中,可以将代码指定为使用场景挂钩。
技术信息
在LukasMac和Gob00st的解决方案的基础上,我为我目前的客户实现了以下解决方案。
这些方法位于一个名为AAA_special_hooks的hook子目录中,位于该目录中的special_hbooks.rb文件中(唯一的文件),这是因为在所有其他条件相同的情况下,hook将按照它们在项目结构中出现的顺序运行,这样,在其他子目录或hooks基目录中指定的任何场景hook之前,都会运行在此创建的hook。
下面附录中的代码是普通的,据我所见,它对任何人都适用。
before钩子的运行原理是设置全局标志,以确保钩子只为一个功能运行一次(根据LukasMac和Gob00st)。该原理被扩展到抽象钩子有两个原因,一是为了简化钩子的一般规范,二是为了与钩子后的实现保持一致。
after钩子用于确定自上次执行场景以来功能是否发生了更改。如果是这样的话,在当前功能发生任何事情之前,将为上一个功能运行after钩子。很明显,这个漏洞可能是因为新功能实际上在前一个功能的后挂钩运行之前就已经启动了,但我看不出这会导致什么问题。然而,最后一个特性不能以这种方式运行after-hook,这就是在at_exit方法中重新实现该代码的原因。
附录-special_hooks.rb代码
def get_formatted_name(feature_name)
formatted_name = feature_name.downcase.gsub(' ', '_')
%w[@ ' , . / ! " £ $ % ^ & * ( ) { } [ ] ; : # ~ ? < > ] + = - ` ¬ |].each { |char| formatted_name.gsub! char, '' }
formatted_name
end
Before do |scenario|
$completed_before_hooks ||= []
$feature_name ||= scenario.feature.name
unless $feature_name == scenario.feature.name
# run after hook for previous feature
begin
send "after_feature_#{get_formatted_name $feature_name}"
rescue NoMethodError
end
end
#run before hook for current feature if not already done
begin
formatted_name = get_formatted_name scenario.feature.name
unless $completed_before_hooks.include? formatted_name
$completed_before_hooks << formatted_name
send "before_feature_#{formatted_name}"
end
rescue NoMethodError
end
$feature_name = scenario.feature.name
end
at_exit do
# don't run final hook if error raised that was not handled
unless $! && $!.status > 1
puts 'EXECUTING FINAL AFTER HOOK... PLEASE WAIT'
begin
send "after_feature_#{get_formatted_name $feature_name}"
rescue NoMethodError
end
puts 'FINAL AFTER HOOK COMPLETED'
end
end
BeforeFeature/AfterFeature挂钩的模拟可以通过用标签@ExecuteBeforeFeature标记功能的第一个场景和用标签@ExecuteAfterFeature标记最后一个场景来实现,然后将标记的Before和After挂钩写如下:
Before('@ExecuteBeforeFeature') do
#code in this method will be executed only before the first scenario or before the feature if only the first scenario is tagged for this hook.
end
After('@ExecuteAfterFeature') do
#code in this method will be executed only after the last scenario or after the feature if only the last scenario is tagged for this hook.
end
对第一个答案的修改对我来说是有效的,带有单引号
Before('@feature_with_expensive_setup') do
unless '@setup_is_done'
# perform expensive setup code here ..
@setup_is_done = true
end
end
您可以使用at_exit实现after功能。