如何在 cucumber cli 之外定义和调用 cucumber steps/scenarios?

How can I define and call cucumber steps/scenarios outside of the cucumber cli?

我有一个工作的黄瓜设置。我的 features/ 文件夹有功能和步骤定义,我可以在命令行调用 cucumber 到 运行 测试套件。

我还有一个单独的脚本,我想启用它来调用一些黄瓜测试。我知道在黄瓜步骤定义中,可以从另一个步骤调用一个步骤。但我不知道如何:

relishApp cucumber api docs,我收集了这个:

require 'cucumber'

# run all features
runtime = Cucumber::Runtime.new
Cucumber::Cli::Main.new([]).execute!(runtime)

这将 运行 我所有的黄瓜测试,就像我从命令行 运行 cucumber 一样,包括格式。但是,我不确定如何使用这种方法来:

我也一直在查看黄瓜源代码以尝试 write/invoke 动态步骤:

require 'cucumber'

Given(/foo/) {}
# this raises an error:
# NoMethodError: undefined method `register_rb_step_definition'
# for Cucumber::RbSupport::RbLanguage:Class
# from /usr/local/lib/ruby/gems/2.0.0/gems/cucumber/2.4.0/lib
#       /cucumber/rb_support/rb_dsl.rb:28
# :in `register_rb_step_definition

# A way to make `'register_rb_step_definition'` succeed:
runtime = Cucumber::Runtime.new
config = Cucumber::Configuration.new
language = Cucumber::RbSupport::RbLanguage.new(runtime, config)
dsl = Cucumber::RbSupport::RbDsl
dsl.rb_language = language
steps = {}
steps["foo"] = dsl.register_rb_step_definiton(/foo (.+)/, ->(args) { puts args })

# Now I have a 'steps' hash like {"foo" => foo_step_object}
# I can call a step like so:
steps["foo"].invoke(["bar"]) # the argument to invoke is an array or hash
# this will print bar to the console like the step proc instructed

这成功地定义和调用了测试,但是有一些缺点:

我一直在查看有关 Cucumber 的一些讨论,似乎有人在推动删除使用 steps 方法调用步骤的功能。换句话说,所有的步骤嵌套都应该通过将代码重构为单独的方法来完成,而不是通过引用其他步骤来完成。我理解这个概念的灵感,但我仍然设想一个用例:

如果使用 cucumber shell 命令 运行,这基本上就是 Cucumber 的工作方式,尽管它要求所有步骤都在功能和场景中 运行 .如果我的应用只需要'steps',但是需要定义一个全局的'feature'和'scenario',那就这样吧,但我还是想只用Ruby,不转到 cucumber shell 命令。

你想要的是

require 'cucumber'
require 'path_to_step_defs.rb'

这样做是加载文件 path_to_step_defs.rb 一次,而且只加载一次。那你就不需要load_step_definitions这个方法了,因为脚本文件已经加载了它需要的

这是对我有用的示例,手动定义和调用步骤:

require 'cucumber' # must require everything; otherwise Configuration cannot be initialized

config = Cucumber::Configuration.new
dsl = Object.new.extend(Cucumber::RbSupport::RbDsl)
rb_language = Cucumber::RbSupport::RbLanguage.new(:unused, config)
step_search = Cucumber::StepMatchSearch.new(rb_language.method(:step_matches), config)

dsl.Given(/hello (.*)/) { |foo| puts "argument given was: #{foo}" }

match = step_search.call('hello world').first
match.step_definition.invoke(match.args) # => argument given was: world

它也会为冗余或不明确的步骤定义引发异常:

dsl.Given(/hello (.*)/) {  }
dsl.Given(/(.*) world/) {  }
step_search.call('hello world')
# => Cucumber::Ambiguous: Ambiguous match of "hello world"

如果您还打算拥有实际的功能文件或步骤定义文件,但不希望将它们包括在内,请记住在没有任何参数的情况下初始化 Configuration 将自动加载一些文件夹:

config = Cucumber::Configuration.new
config.autoload_code_paths
# => ["features/support", "features/step_definitions"]

config = Cucumber::Configuration.new(autoload_code_paths: [])
config.autoload_code_paths
# => []