2012-02-09 37 views
15

方案断言一个特定的异常在黄瓜抛出

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

最直观的方式来写黄瓜步骤可能会是这样的

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

问题

有两个问题,我必须解决:

  1. 当引发异常时,第一步不应该失败。
  2. 第一步引发的异常应该可以通过第二步访问,以便执行某些断言魔术。

Unelegant和繁琐的解决方案

我已经能够拿出的缓存例外的第一步,把它变成一个实例变量,第二步骤后才能访问的最佳方法,像这样:

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 

然而,这使得第一步或多或少没用的情况下,我希望它失败,它需要一个实例变量,这是从来没有一件好事。

那么,任何人都可以帮助我至少减少繁琐的解决方案吗?还是应该以不同的方式写我的功能?任何帮助将非常感激。

+0

现在,这个问题写得很好!肯定值得一个好的答案(对不起,我不能拿出一个):) :) – user562529 2012-03-08 02:24:11

+0

非常感谢@ user562529。不幸的是我有这样的感觉,实际上这个问题实际上并没有简单的解决方案,所以我可能只是打开一个黄瓜问题,并希望他们实施一些实用的东西。 – JLimperg 2012-03-08 21:43:29

回答

5

我想过这个问题再一次,也许答案是:

没有很好的解决方案,因为Given-When-Then -Scheme在您的案件中侵犯。 你期望“那么应该抛出异常”是“当我做一些不需要的东西时”的结果。

但是,当你想到它,这是不正确的!这个例外不是这个动作的结果,实际上这个例外只是表明“When” - 语句失败。

我到该溶液中。将在更高层次上进行测试:

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" 

或这些的组合。

然后,您将在程序中“缓存异常” - 这非常有意义,因为无论如何您最有可能需要这样做。

你说过的两个问题也会解决。

如果你真的必须测试异常

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

由于考虑 - 当 - 当时的方案是违反无论如何,我只想写

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处发现更多文档。

+0

噢,我刚刚读了你的第一句话。不要介意,当你写作一个图书馆时,答案或多或少是无用的。 – user562529 2012-03-13 15:51:14

+1

感谢您的广泛写作。不幸的是,你的评论也碰到了头。 ;) 但是,你说的话可能仍然是正确的,并且与这个问题有关:Cucumber可能只是为了深入挖掘图书馆的错误处理而设计的。好像我会坚持使用RSpec解决这个问题。 – JLimperg 2012-03-25 15:54:16

+0

我遇到了同样的问题,并得出结论,虽然Cucumber是一个伟大的库用于测试应用程序,但它不太适合测试库。 Cucumber最大的优势在于它可以被没有阅读代码的人阅读,很少有非开发人员可能有兴趣阅读开发人员库的规范,所以我已经在Cucumber上为应用程序和RSpec定义了库。 对于像我这样的人在开发应用程序时发现这个页面,这是一个很好的答案。在这种情况下,在更高层次上编写规范更合适。 – 2013-02-10 16:23:50

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 I should see an error 

这可能不是正是你所希望看到的,但它可能是一个对于遇到此页面的某些人可接受的解决方法。我认为这将取决于异常类型,因为如果异常在任何级别都没有获救,那么该场景仍然会失败。我已经使用这种方法主要用于路由错误到目前为止,这工作得很好。

-1

我是从谁的人在行为驱动开发情况使用黄瓜功能的角度回答,所以要么接受,要么离开它...

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

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

这听起来像你的测试用例(即如果我这样做,那么这个异常应该抛出)可以单位或集成测试的候选人 - 在我的情况下,我们会使用一些嘲弄或单元测试框架。

我的建议是重新评估你的功能场景,看看他们是否真的在测试你想要测试的东西。从个人经验来看,我发现如果我的测试课变得异常复杂,那么我的功能是错误的。

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的匹配器,但重要的部分是->(波长);这允许参考throw_an_exception!方法传递。

我希望有帮助!