ruby - éviter - try catch finally java




Affirmer qu'une exception particulière est levée dans Concombre (3)

Scénario

J'écris une bibliothèque (pas Ruby on Rails) pour laquelle j'aimerais avoir des fonctionnalités très détaillées de Cucumber. Cela inclut notamment la description des erreurs / exceptions qui devraient être jetées dans divers cas.

Exemple

La façon la plus intuitive d'écrire les étapes du concombre serait probablement quelque chose comme

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

Problème

Il y a deux questions que je dois aborder:

  1. La première étape ne doit pas échouer lorsqu'une exception est levée.
  2. L'exception que la première étape jette devrait être accessible à la deuxième étape afin de faire de la magie d'assertion.

Solution unelegant et encombrante

La meilleure approche que j'ai trouvée est de mettre en cache l'exception dans la première étape et de la placer dans une variable d'instance à laquelle la deuxième étape peut accéder, comme ceci:

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

Cependant, cela rend la première étape plus ou moins inutile dans les cas où je ne veux pas qu'elle échoue, et elle nécessite une variable d'instance, ce qui n'est jamais une bonne chose.

Alors, quelqu'un peut-il m'aider avec une solution au moins moins encombrante? Ou devrais-je écrire différemment mes caractéristiques? Toute aide serait très appréciée.


Il est possible de lever une exception dans un bloc When , puis de faire des assertions à son sujet dans les blocs Then suivants.

En utilisant votre exemple:

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

Cet exemple utilise les coupleurs de RSpec mais la partie importante est la -> (Lambda); ce qui permet la référence à la throw_an_exception! méthode à transmettre.

J'espère que ça aide!


J'y ai pensé une fois de plus, et peut-être que la réponse est:

Il n'y a pas de solution élégante, parce que le " Given-When-Then -Scheme" est violé dans votre cas. Vous vous attendez à ce que "Puis une exception soit levée" est le résultat de "Quand je fais quelque chose d'indésirable".

Mais quand on y pense, ce n'est pas vrai! L'exception n'est pas le résultat de cette action, en fait, l'exception montre simplement que l'état "Quand" a échoué.

Ma solution à cela serait de tester à un niveau supérieur:

When I do something unwanted
Then an error should be logged

ou

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

ou

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

ou une combinaison de ceux-ci.

Ensuite, vous «mettre en cache l'exception» dans votre programme - ce qui est parfaitement logique, car vous avez probablement besoin de le faire de toute façon.

Les deux problèmes que vous avez mentionnés seraient également résolus.

Au cas où vous devriez vraiment tester des exceptions

Eh bien, je suppose que le concombre n'est pas la bonne suite de tests, hmm? ;-)

Comme le "Given-When-Then-Scheme" est violé de toute façon, j'écrirais simplement

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

et dans les définitions d'étape quelque chose comme (non testé, s'il vous plaît corrigez-moi si vous l'essayez)

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

Comme je l'ai dit plus haut, c'est horriblement mauvais, car le système est brisé, mais cela servirait le but, n'est-ce pas? ;-)

Vous trouverez d'autres documents pour tester les erreurs sur les attentes de rspec .


Une option consiste à marquer le scénario avec @allow-rescue et à vérifier le code de sortie et d'état de la page. Par exemple

Dans 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

Dans 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

Ou bien:

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

Cela peut ne pas être exactement ce que vous espériez, mais cela pourrait être une solution de contournement acceptable pour certaines personnes qui rencontrent cette page. Je pense que cela dépendra du type d'exception, car si l'exception n'est récupérée à aucun niveau, le scénario échouera toujours. J'ai principalement utilisé cette approche pour les erreurs de routage jusqu'à présent, ce qui a bien fonctionné.





cucumber