断言在Cucumber中抛出了一个特殊的exception

脚本

我正在写一个库(没有Ruby on Rails),我想要非常详细的Cucumberfunction。 这尤其包括描述在各种情况下应该抛出的错误/exception。

编写Cucumber步骤最直观的方法可能就是这样

When I do something unwanted Then an "ArgumentError" should be thrown 

问题

我必须解决两个问题:

  1. 抛出exception时,第一步不应该失败。
  2. 第一步抛出的exception应该可以被第二步访问,以便做一些断言魔术。

不雅和繁琐的解决方案

我能够提出的最好方法是在第一步中缓存exception并将其放入第二步可以访问的实例变量中,如下所示:

 When /^I do something unwanted$/ do begin throw_an_exception! rescue => @error end end Then /^an "(.*)" should be thrown$/ do |error| @error.class.to_s.should == error end 

但是,在我希望它失败的情况下,这使得第一步或多或少无用,并且它需要一个实例变量,这绝不是一件好事。

那么,任何人都可以帮助我解决至少不那么麻烦的解决方案吗? 或者我应该以不同的方式编写我的function? 任何帮助将非常感激。

我再一次想到了,也许答案是:

没有优雅的解决方案,因为在您的情况下违反了Given-When-Then -Scheme。 你期望“然后应该抛出exception”是“当我做一些不需要的东西”时的结果。

但是当你想到它时,这不是真的! exception不是此操作的结果,实际上exception只是显示“When”-Statement失败。

我的解决方案是在更高级别进行测试:

 When I do something unwanted Then an error should be logged 

要么

 When I do something unwanted Then the user should get an error message 

要么

 When I do something unwanted Then the program should be locked in state "error" 

或这些的组合。

然后你会在程序中“缓存exception” – 这很有道理,因为你最有可能需要这样做。

你所陈述的两个问题也将得到解决。

如果你真的必须测试exception

好吧,我猜黄瓜不是正确的测试套件,嗯? 😉

因为无论如何违反了Given-When-Then-Scheme,我只会写

 When I do something unwanted it should fail with "ArgumentError" 

并且在步骤定义中有类似的东西(未经测试,如果您尝试,请纠正我)

 When /^I do something unwanted it should fail with "(.*)"$/ do |errorstring| expect { throw_an_exception! }.to raise_error(errorstring) end 

如上所述,由于计划被打破,这是非常错误的,但它会达到目的,不是吗? 😉

您可以在rspec期望的测试错误中找到更多文档。

一种选择是使用@allow-rescue标记场景并检查页面的输出和状态代码。 例如

my_steps.rb

 Then(/^the page (?:should have|has) content (.+)$/) do |content| expect(page).to have_content(content) end Then(/^the page should have status code (\d+)$/) do |status_code| expect(page.status_code.to_s).to eq(status_code) end Then /^I should see an error$/ do expect(400..599).to include(page.status_code) end 

my_feature.feature

 @allow-rescue Scenario: Make sure user can't do XYZ Given some prerequisite When I do something unwanted Then the page should have content Routing Error And the page should have status code 404 

或者:

 @allow-rescue Scenario: Make sure user can't do XYZ Given some prerequisite When I do something unwanted Then I should see an error 

这可能不是您所希望的,但对于遇到此页面的人来说,这可能是一种可接受的解决方法。 我认为它将取决于exception的类型,因为如果exception没有在任何级别获救,那么该方案仍将失败。 到目前为止,我主要使用这种方法来处理路由错误,这种方法运行良好。

可以在When块中引发exception,然后在下面的Then块中对它进行断言。

使用你的例子:

 When /^I do something unwanted$/ do @result = -> { throw_an_exception! } end Then /^an "(.*)" should be thrown$/ do |error| expect{ @result.call }.to raise_error(error) end 

该示例使用RSpec的匹配器,但重要的部分是-> (Lambda); 它允许引用throw_an_exception! 要传递的方法。

我希望有所帮助!

我是从在行为驱动的开发情况下使用Cucumberfunction的人的角度回答的,所以接受或离开它……

应编写方案来测试应用程序的“function”或function,而不是用于测试代码本身。 一个例子是:

 When the service is invoked Then a success code should be returned 

这听起来像你的测试用例(即如果我这样做,那么应该抛出这个exception)是unit testing或集成测试的候选者 – 在我的例子中,我们将使用一些模拟或unit testing框架。

我的建议是重新评估您的function方案,看看它们是否真的在测试您打算测试的内容。 根据个人经验,我发现如果我的测试类变得exception复杂,那么我的function是“错误的”。