Утверждая, что конкретное исключение выбрасывается в огурец - PullRequest
17 голосов
/ 10 февраля 2012

Сценарий

Я пишу библиотеку (без Ruby on Rails), для которой я хотел бы иметь очень подробные функции Cucumber. Особенно это касается описания ошибок / исключений, которые следует выдавать в различных случаях.

Пример

Наиболее интуитивно понятный способ написания шагов Cucumber, вероятно, будет выглядеть примерно так:

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

Задача

Есть две проблемы, на которые мне нужно ответить:

  1. Первый шаг не должен завершиться неудачей при возникновении исключения.
  2. Исключение состоит в том, что броски первого шага должны быть доступны для второго шага, чтобы сделать магию утверждения.

Нелегкое и громоздкое решение

Лучший подход, который мне удалось придумать, - это кэширование исключения на первом шаге и помещение его в переменную экземпляра, к которой может получить доступ второй шаг, например:

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

Однако это делает первый шаг более или менее бесполезным в тех случаях, когда я не не хочу, чтобы он потерпел неудачу, и для него требуется переменная экземпляра, что никогда не бывает хорошо.

Итак, кто-нибудь может мне помочь с хотя бы менее громоздким решением? Или я все равно должен написать свои функции по-другому? Любая помощь будет высоко ценится.

Ответы [ 4 ]

6 голосов
/ 13 марта 2012

Я подумал об этом еще раз, и, возможно, ответ:

Не существует элегантного решения, поскольку в вашем случае нарушается схема Given-When-Then -Scheme. Вы ожидаете, что «Тогда должно быть выброшено исключение» - это результат «Когда я делаю что-то нежелательное».

Но когда вы думаете об этом, это не так! Исключение не является результатом этого действия, на самом деле исключение просто показывает, что условие «Когда» не выполнено.

Мое решение для этого было бы проверить на более высоком уровне:

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

Как сказано выше, это ужасно неправильно, поскольку схема нарушена, но она послужит цели, не так ли? ; -)

Дополнительную документацию вы найдете при ошибках тестирования при ожиданиях rspec .

4 голосов
/ 03 декабря 2015

Один из вариантов - пометить сценарий @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 the page should have content Routing Error
  And the page should have status code 404

или альтернативно:

@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 голос
/ 22 января 2017

Можно вызвать исключение в блоке 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 соответствия, но важной частью является -> (Lambda);что позволяет передавать ссылку на метод throw_an_exception!.

Надеюсь, это поможет!

0 голосов
/ 10 марта 2016

Я отвечаю с точки зрения кого-то, кто использует функции Cucumber в ситуации с поведенческим развитием, поэтому возьмите его или оставьте ...

Сценарии должны быть написаны для проверки «функции» или функциональности приложения, а не для тестирования самого кода. Примером является:

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

Похоже, ваш тестовый пример (т. Е. Если я это сделаю, то должно быть выброшено это исключение) является кандидатом на модульное или интеграционное тестирование - в моем случае мы использовали бы некоторую среду для Mocking или unit-тестирования.

Мое предложение состояло бы в том, чтобы пересмотреть ваши сценарии функций, чтобы увидеть, действительно ли они тестируют то, что вы намереваетесь протестировать. Исходя из личного опыта, я обнаружил, что если мои тестовые занятия становятся необычно сложными, то мои функции «неправильны».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...