如何在黄瓜cli之外定义和调用黄瓜步骤/场景?

时间:2016-07-23 20:50:51

标签: ruby cucumber

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

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

  • 需要我的功能文件
  • 需要我的步骤文件
  • 并运行一系列功能/方案/步骤。

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

require 'cucumber'

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

这将以与从命令行运行cucumber完全相同的方式运行我的所有黄瓜测试,包括格式。但是,我不确定如何使用这种方法:

  • 运行特定功能或步骤
  • 继续执行脚本的其余部分(因为execute!退出程序)。

我也一直在寻找黄瓜源代码来尝试动态编写/调用步骤:

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

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

  • 有必要将步骤名称和参数分开。理想情况下,我希望能够调用step("foo bar")之类的内容,而不是写steps["foo"].invoke(["bar"])。在我当前尝试调用步骤时,将忽略定义中的正则表达式。
  • 如果使用CLI输出格式化程序,那就太好了。

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

  • 在全球范围内定义正则表达式匹配器
  • 提供字符串,查找正则表达式匹配,并执行步骤
  • 使用格式化程序输出

如果Cucumber使用cucumber shell命令运行,这基本上就是这样的,尽管它要求所有步骤都在一个功能中运行。场景。如果我的应用程序只需要“步骤”,但需要定义全局“功能”和“场景”,那么就这样吧,但我仍然只想使用Ruby而不是转向cucumber shell命令。

2 个答案:

答案 0 :(得分:2)

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

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
# => []

答案 1 :(得分:0)

你想要的是

require 'cucumber'
require 'path_to_step_defs.rb'

这样做只会加载文件path_to_step_defs.rb一次,而且只加载一次。然后,您不需要load_step_definitions方法,因为脚本文件已经加载了它所需的内容。