在RSpec中是否存在与Cucumber的“情景”相同或者我使用RSpec的错误方式?

我对Cucumber的情景的简洁性和实用性印象深刻,它们是测试不同情况的一种很好的方式。

例如黄瓜情景

Feature: Manage Users In order to manage user details As a security enthusiast I want to edit user profiles only when authorized Scenario Outline: Show or hide edit profile link Given the following user records | username | password | admin | | bob | secret | false | | admin | secret | true | Given I am logged in as "" with password "secret" When I visit profile for "" Then I should  Examples: | login | profile | action | | admin | bob | see "Edit Profile" | | bob | bob | see "Edit Profile" | | | bob | not see "Edit Profile" | | bob | admin | not see "Edit Profile" | 

(代码取自Ryan Bates的更多关于黄瓜的截屏video )

RSpec中是否有等价物?

我想在RSpec中做同样的事情,并通过将不同的测试减少到场景表中的一行来干掉我的代码。

虽然我可以自己编写代码来实现这一点,但我正在考虑它的事实让我想到了两件事

  1. 如果这很有用,它可能已经存在,在哪种情况下如何使用它?

  2. 如果它不存在它表明它不应该这样做,并且我正在接近问题,我应该如何重新思考我的RSpec方法?

哪个答案是对的,如果它有用,我该怎么做?

尝试以下方法。 我喜欢它的结果。

 describe StateDateMethods do before :each do @product = OpenStruct.new @product.extend StateDateMethods end def parse_date(unparsed_date_value) unless unparsed_date_value.nil? DateTime.strptime(unparsed_date_value, '%m/%d/%Y') end end context '#pre_order?' do examples = [ # [visible_on, pre_order_on, for_sale_on] => method_result { :inputs => [nil, nil, nil], :expected => false }, { :inputs => ['1/1/2001', nil, nil], :expected => false }, { :inputs => ['1/1/2001', '1/1/2001', nil], :expected => true }, { :inputs => ['1/1/2001', '1/2/2001', nil], :expected => true }, { :inputs => ['1/1/2001', '1/1/2001', '1/2/2001'], :expected => false }, { :inputs => ['1/1/2001', '1/1/2001', '1/1/3001'], :expected => true }, { :inputs => ['1/1/2001', '1/1/3001', '1/2/3001'], :expected => false }, { :inputs => ['1/1/3001', '1/1/3001', '1/2/3001'], :expected => false }, { :inputs => ['1/1/2001', nil, '1/1/2001'], :expected => false }, { :inputs => ['1/1/2001', nil, '1/1/3001'], :expected => false } ] examples.each do |example| inputs = example[:inputs] it "should return #{example[:expected].inspect} when visible_on == #{inputs[0].inspect}, pre_order_on == #{inputs[1].inspect}, for_sale_on == #{inputs[2].inspect}" do @product.visible_on = parse_date(inputs[0]) @product.pre_order_on = parse_date(inputs[1]) @product.for_sale_on = parse_date(inputs[2]) @product.pre_order?.should == example[:expected] end end end end 

我认为这给了两个世界的最好,因为它让我不再重复自己,它为每个条件创造了不同的测试。

这是失败的样子:

 ....F..... Failures: 1) StateDateMethods#pre_order? should return false when visible_on == "1/1/2001", pre_order_on == "1/1/2001", for_sale_on == "1/2/2001" Failure/Error: @product.pre_order?.should == example[:expected] expected: false got: true (using ==) # ./spec_no_rails/state_date_methods_spec.rb:40:in `block (4 levels) in ' Finished in 0.38933 seconds 10 examples, 1 failure Failed examples: rspec ./spec_no_rails/state_date_methods_spec.rb:35 # StateDateMethods#pre_order? should return false when visible_on == "1/1/2001", pre_order_on == "1/1/2001", for_sale_on == "1/2/2001" 

这就是所有绿色的样子:

 .......... Finished in 0.3889 seconds 10 examples, 0 failures 

我在RSpec Scenario Outlines:Multiple Test Cases问题中给出了一个适用于RSpec的例子。 我给出了一个可能的解决方案,但如果你找到一个更好的解决方案,请告诉我。

我不会以这种方式使用RSpec。 应该使用RSpec将行为一次驱动到类中一个小行为。 由于每个行为都是唯一的,因此您应该使用不同的规范来定义它。

在上面的方案中,您可能具有指定行为的规范,例如:

 it "should allow user to edit his own profile" it "should allow admin to edit other users profile" it "should not allow non-admin to edit admin profile" it "should not allow anonymous user to edit any profile" 

还有一件事,使用RSpec来驱动应用程序的多个层次并不是一个好主意。 换句话说,当您定义控制器时,您应该模拟与模型的交互等。