2012-02-09 9 views
15

Escenarioque afirme que una excepción en particular se lanza en Pepino

estoy escribiendo una biblioteca (sin Ruby on Rails) para los que me gustaría tener características muy detalladas de pepino. Esto incluye especialmente la descripción de errores/excepciones que deberían arrojarse en varios casos.

Ejemplo

La forma más intuitiva para escribir los pasos de pepino, probablemente sería algo así como

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

Problema

Hay dos cuestiones que tengo que abordar:

  1. El primer paso no debe fallar cuando se lanza una excepción.
  2. La excepción de que el primer paso arroja debe ser accesible al segundo paso para poder hacer algo de aserción mágica.

Unelegant y engorroso Solución

El mejor método que he sido capaz de llegar a almacenar en caché es la excepción en el primer paso y ponerlo en una variable de instancia que la segunda etapa se puede acceder, de este modo:

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 

sin embargo, esto hace que el primer paso más o menos inútil en los casos en que no quiere que falte, y se requiere una variable de instancia, que nunca es una buena cosa.

Entonces, ¿alguien puede ayudarme con una solución al menos menos engorrosa? ¿O debería escribir mis características de manera diferente de todos modos? Cualquier ayuda sería muy apreciada.

+0

¡Ahora esa pregunta está muy bien escrita! Merece una buena respuesta con seguridad (lo siento, no pude encontrar una) :) – user562529

+0

Muchas gracias @ user562529. Lamentablemente, tengo la sensación de que en realidad no hay una solución fácil para este problema, por lo que podría abrir un problema de Pepino y esperar que implementen algo práctico. – JLimperg

Respuesta

5

pensaba en ello, una vez más, y tal vez la respuesta es:

No hay una solución elegante, debido a que el Given-When-Then -Esquema es violada en su caso. Usted espera que "Entonces se debe lanzar una excepción" es el resultado de "Cuando hago algo no deseado".

¡Pero cuando lo piensas, esto no es verdad! La excepción no es el resultado de esta acción, de hecho, la excepción solo muestra que el "Cuando" - Fracaso.

Mi solución a esto sería poner a prueba a un nivel superior:

When I do something unwanted 
Then an error should be logged 

o

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

o

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

o una combinación de éstos.

Luego "caché la excepción" en su programa, lo cual tiene perfecto sentido, ya que lo más probable es que tenga que hacer eso de todos modos.

Los dos problemas que ha indicado se resolverán también.

En caso de que realmente debe probar excepciones

bueno, supongo que entonces el pepino no es el conjunto de pruebas bien, eh? ;-)

A medida que el dado por Al-Entonces-Esquema es violado todos modos, simplemente me gustaría escribir

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

y definiciones en el paso algo parecido (no probado, por favor, corríjanme si lo intentas)

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

Como dije anteriormente, eso es terriblemente incorrecto ya que el plan está roto, pero serviría para el propósito, ¿no? ;-)

Encontrará más documentación en los errores de prueba at rspec expectations.

+0

Oh, bueno ... Acabo de leer tus primeras oraciones de nuevo. No importa si la respuesta es más o menos inútil como escribir una biblioteca. – user562529

+1

Gracias por este extenso informe. Desafortunadamente, tu comentario también da en el clavo. ;) Sin embargo, lo que diga probablemente sea aún correcto y relevante para este problema: Pepino podría no estar diseñado con el propósito de profundizar en el manejo de errores de una biblioteca. Parece que me quedaré con RSpec para este problema. – JLimperg

+0

Me he encontrado con este mismo problema y he llegado a la conclusión de que, si bien Cucumber es una gran biblioteca para probar aplicaciones, no es muy adecuado para probar bibliotecas. La mayor fortaleza de Cucumber es que puede leerla gente que no lee código y muy pocos no desarrolladores pueden estar interesados ​​en leer las especificaciones de una biblioteca de desarrolladores, así que me he decidido por Cucumber para aplicaciones y RSpec para bibliotecas. . Esta es una buena respuesta para personas como yo que encuentran esta página al desarrollar una aplicación. En ese caso, escribir la especificación en un nivel superior es más apropiado. –

4

Una opción es marcar el escenario con @allow-rescue y verificar la salida de la página y el código de estado. Por ejemplo

En 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 

En 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 

o alternativamente:

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

Esto puede no ser exactamente lo que usted esperaba, pero podría ser una solución aceptable para algunas personas que se encuentran con esta página. Creo que dependerá del tipo de excepción, ya que si la excepción no se rescata en ningún nivel, el escenario seguirá fallando. He utilizado este enfoque principalmente para errores de enrutamiento hasta el momento, lo que ha funcionado bien.

-1

Estoy respondiendo desde la perspectiva de alguien que utiliza características de pepino en una situación de desarrollo guiado por comportamiento, a fin de tomar o lo dejas ...

Los escenarios deben ser escritos para probar una 'característica' o funcionalidad de la aplicación, en lugar de ser utilizado para probar el código en sí. Un ser ejemplo:

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

Parece que su caso de prueba (es decir, Si hago esto, entonces esta excepción se debe tirar) es un candidato para la unidad o las pruebas de integración - en mi caso, nos usamos alguna burla o se marco de prueba de la unidad.

Mi sugerencia sería volver a evaluar sus escenarios de características para ver si realmente están probando lo que pretende que prueben. Por experiencia personal, he descubierto que si mis clases de prueba se vuelven anormalmente complejas, entonces mis características son 'incorrectas'.

1

Es posible hacer una excepción en un bloque When y luego hacer afirmaciones al respecto en los siguientes bloques Then.

Usando su ejemplo:

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 

Ese ejemplo se utiliza comparadores RSpec 's pero lo importante es la -> (Lambda); que permite pasar la referencia al método throw_an_exception!.

Espero que ayude!

Cuestiones relacionadas