2011-01-13 7 views
15

Estoy impresionado por la brevedad y la utilidad de los Escenarios de pepino, son una excelente manera de probar una gran cantidad de casos diferentes.¿Hay un equivalente en RSpec para "Escenarios" de Cucumber o estoy usando RSpec de la manera incorrecta?

por ejemplo ejemplo pepino escenario

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 "<login>" with password "secret" 
    When I visit profile for "<profile>" 
    Then I should <action> 

    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" | 

(Código tomado de Ryan Bates' More on Cucumber Screencast)

¿Existe un equivalente en RSpec?

Me gustaría hacer lo mismo en RSpec y SECAR mi código al reducir diferentes pruebas hasta una fila en una tabla de escenarios.

A pesar de que podría escribir el código para hacer esto mismo, el hecho de que estoy teniendo en cuenta que me hace pensar dos cosas

  1. Si esto es útil es probable que ya existe en cuyo caso, ¿cómo lo uso ¿eso?

  2. Si no existe, sugiere que no se debe hacer de esta manera y que estoy abordando el problema incorrectamente, ¿cómo debería replantear mi enfoque a RSpec?

¿Cuál es la respuesta correcta y si es útil, cómo lo hago?

Respuesta

20

Pruebe el siguiente enfoque. Me gusta como salió.

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 

creo que esto da lo mejor de ambos mundos, ya que me mantiene de repetirme, y se crea una prueba diferente para cada condición.

Esto es lo que un fracaso se ve así:

....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 <top (required)>' 

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" 

Y es aquí lo que todas las miradas verdes como:

.......... 

Finished in 0.3889 seconds 
10 examples, 0 failures 
+0

Me gusta - buen enfoque –

+0

Gran respuesta. recuerda bastante a las tablas de datos de Specs2. –

1

No utilizaría RSpec de esta manera. RSpec se debe usar para llevar el comportamiento al comportamiento pequeño de clase uno a la vez. Como cada comportamiento es único, debe usar una especificación diferente para definirlo.

en el escenario anterior que podría tener características que especifican el comportamiento como:

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" 

Una cosa más, no es una buena idea usar RSpec a conducir a través de múltiples capas de la aplicación. En otras palabras, cuando defina sus controladores, debe simular las interacciones con sus modelos, etc.

+0

Hola cheezy, gracias por eso. Aunque estaba usando un ejemplo de prueba de integración de pepino, sabía (aunque no siempre lo logro) la granularidad que debería usarse con RSpec.Sin embargo, mi pregunta era menos sobre esa especificación particular y más sobre la idea de tener escenarios guiados por tablas. ¿Sabes si RSpec lo admite? –

+0

No he visto una gema que proporcione tablas en rspec. De nuevo, no puedo pensar en un ejemplo en el que esto sea apropiado. – Cheezy

+1

En la misma línea, hay una gema que proporciona las palabras clave Given/When/Then en rspec con las que he estado jugando un poco. https://github.com/jimweirich/rspec-given – Cheezy

Cuestiones relacionadas