Огірок JVM: Перевірте, чи виключено правильне виключення

Я трохи здивований тим, що не можу знайти відповідь на це питання онлайн. У будь-якому випадку, коли ви використовуєте Junit, щоб перевірити правильність виключення, я б зробив щось на зразок цього:

@Test(expected = NullPointerException.class)
    public void testExceptionThrown(){

        taskCreater.createTask(null);
    }

Як видно вище, це дуже елегантний спосіб тестування, якщо виключено, але як я можу досягти такої ж елегантності при використанні огірка JVM? Мій тест виглядає так прямо зараз:

@Then("the user gets a Null pointer exception$")
    public void null_exception_thrown() {
        boolean result = false;
        try {
              taskCreater.createTask(null);
        } catch (NullPointerException e) {

            result = true;
         }
      assertTrue(result);
    }

Це потворно !!

14
Особисто я не впевнений, що ваша припущення (майже) коли-небудь отримувати винятки в пройденому тестовому випадку. Огірок написано з точки зору користувача, і користувач ніколи не повинен знати, ніж виключено виняток - програма повинна якось вирішити проблему, показуючи якесь повідомлення, яке говорить користувачеві, що вони не повинні робити те, що вони просто пробували чи щось подібне.
додано Автор Dylanthepiguy, джерело
правильне відступ
додано Автор Infested, джерело

7 Відповіді

Тестування не-щасливого шляху може бути важким. Ось хороший спосіб, який я знайшов, щоб це зробити з огірком.

Scenario: Doing something illegal should land you in jail
    Then a failure is expected
    When you attempt something illegal
    And it fails.

Добре, не стріляйте мене, тому що я розміщую Тоді перед тим, як When , я просто думаю, що він читає краще, але вам не потрібно це робити.

Я зберігаю мої винятки в об'єкті (об'єкт, орієнтований на огірок), але ви також можете це зробити у вашому кросовому файлі, але це буде обмежувати вас пізніше.

public class MyWorld {
    private boolean expectException;
    private List exceptions = new ArrayList<>();

    public void expectException() {
        expectException = true;
    }

    public void add(RuntimeException e) {
        if (!expectException) {
            throw e;
        }
        exceptions.add(e);
    }

    public List getExceptions() {
        return exceptions;
    }
}

Тоді ваші кроки досить прості:

@Then("a failure is expected")
public void a_failure_is_expected() {
    myWorld.expectException();
}

У кроці, де ви (хоча б іноді) очікуєте винятку, спіймайте його і додайте його у світ.

@When("you attempt something illegal")
public void you_attempt_something_illegal() {
    try {
        myService.doSomethingBad();
    } catch (RuntimeException e) {
        world.add(e);
    }
}

Тепер ви можете перевірити, чи було записано виняток у світі.

@And("it fails")
public void it_fails() {
    assertThat(world.getExceptions(), is(not(empty()));
}

Найцінніше з цього підходу є те, що він не проковтне виняток, коли ви цього не очікуєте.

11
додано
Мені подобається цей підхід, я думаю, що ця лінія } catch (RuntimeException e) { може бути замінена на } catch (YourExpectedException e) {, отже, якщо ви не очікуєте виключення кинутий тест не зможе
додано Автор Olivier Boissé, джерело

Ви пробували використовувати анотацію junit @Rule з ExpectedException, як це:

@Rule
public ExpectedException expectedEx = ExpectedException.none();

@Then("the user gets a Null pointer exception$")
public void null_exception_thrown() {
    expectedEx.expect(NullPointerException.class);
    //expectedEx.expectMessage("the message");
    taskCreater.createTask(null);
}
7
додано
Чи дійсно це працює? Відповідно, це не має ніякого впливу: github.com/cucumber/cucumber-jvm/issues/393
додано Автор bcoughlan, джерело
це правильний підхід.
додано Автор Boris the Spider, джерело
Здається, у огірці ігноруються правила junit
додано Автор Olivier Boissé, джерело

Ніколи не використовував Огірок, але було б

    public void null_exception_thrown() {
            try {
                  taskCreater.createTask(null);
                  fail("Null Pointer Expected");
            } catch (NullPointerException e) {

               //Do Nothing
             }
        }

працювати для вас?

3
додано

Тестування поведінки перевіряє, чи відповідає ваш проект технічним вимогам, і я сумніваюся, що користувач сподівається на використання NullPointerException при використанні системи.

На мій погляд (я не знайомий з вашим проектом), винятки слід перевіряти лише під час тестування, оскільки вони відповідають несподіваній помилці або помилці користувача.

Дуже незвично перевіряти винятки під час тестів на поведінку. Якщо під час тесту виключено виключення, воно має вийти з ладу.

наприклад:

test.feature

Given that I have a file "users.txt"
And I try to import users /* If an Exception is thrown here, the test fails */
Then I should see the following users: /* list of users */

У моєму тестовому модулі я б мав:

@Test(expected = MyException.class)
public void importUsersShouldThrowMyExceptionWhenTheFileIsNotFound() {
   //mock a call to a file and throw an exception
    Mockito.when(reader.readFile("file.txt").thenThrow(new FileNotFoundException());

    importer.importUsers();
}
3
додано
"Користувач" не обов'язково є людиною. Інтерфейс введення, який використовує тести, може бути API.
додано Автор bcoughlan, джерело

Я вважаю, огірок призначений для тестування тестів на вищий рівень, ніж тести на рівні нижчого рівня, тому що в цьому випадку ми будемо тестувати структуру, протилежну поведінці , що не є бажаним використанням рамки Огірок.

0
додано

Я пропоную вам скористатися org.assertj.assertj-core .

Завдяки класу Assertions , ви можете спростити своє твердження, як показано нижче:

@Then("the user gets a Null pointer exception$")
public void null_exception_thrown() {
    Assertions.assertThatThrownBy(() -> taskCreater.createTask(null)).
               isInstanceOf(NullPointerException.class);
}
0
додано

Я мав очікуване ім'я винятку в етапі функції. для прикладу тесту калькулятора

Ось запис мого файлу функцій для виключення розділу:

Scenario: Dividing a number with ZERO
Given I want to test calculator
When I insert 5.5 and 0.0 for division
Then I got Exception ArithmeticException

Отже, ви можете побачити, я додав ім'я виключення. Отже, у визначенні кроку я отримую назву винятку.

Тепер нам потрібно отримати виняток, розділяючи ZERO і вводячи змінну. І отримайте цю змінну для порівняння свого імені класу (ім'я виключення)

так, за визначенням кроку, де я поділяю на нуль

private Exception actualException;
 @When("^I insert (.+) and (.+)for division$")
public void iInsertAndForDivision(double arg0, double arg1) throws Throwable {
    try {
        result = calculator.div(arg0, arg1);
    } catch (Exception e) {
        actualException =e;
    }
}

І мені потрібно визначити кроки для перевірки винятку

  @Then("^I got Exception (.+)")
public void iGotArithmeticException(String aException) throws Throwable {        
Assert.assertEquals("Exception MissMatch",aException,actualException.getClass().getSimpleName());
}

The complete project can be seen here : Steps for cucumber

0
додано
ІТ КПІ - Java
ІТ КПІ - Java
436 учасників