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

时间:2012-02-09 22:35:26

标签: ruby exception-handling cucumber

方案

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

示例

编写Cucumber步骤最直观的方法可能就像

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

问题

我必须解决两个问题:

  1. 抛出异常时,第一步不应该失败。
  2. 第一步抛出的异常应该可以进入第二步,以便做一些断言魔术。
  3. 不雅和繁琐的解决方案

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

    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
    

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

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

4 个答案:

答案 0 :(得分:6)

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

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

但是当你想到它时,这不是真的!异常不是此操作的结果,实际上异常只是显示“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"

或这些的组合。

然后你会在你的程序中“缓存异常” - 这非常有意义,因为你最有可能需要这样做。

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

如果你真的必须测试异常

嗯,我猜黄瓜不是正确的测试套件,嗯? ; - )

无论如何违反了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

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

您可以在测试错误at rspec expectations找到更多文档。

答案 1 :(得分:4)

一种选择是使用@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

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

答案 2 :(得分:1)

可以在When块中引发异常,然后在以下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!方法的引用。

我希望有所帮助!

答案 3 :(得分:-1)

我从行为驱动型开发环境中使用Cucumber功能的人的角度回答,所以接受或离开它......

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

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

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

我的建议是重新评估您的功能方案,看看它们是否真的在测试您打算测试的内容。从个人经验来看,我发现如果我的测试类变得异常复杂,那么我的功能就是错误的。'