JUnit путаница: использовать "extends TestCase" или "@Test"?

Я нашел правильное использование (или, по крайней мере, документацию) JUnit очень запутанным. Этот вопрос служит как будущей ссылкой, так и реальным вопросом.

Если я правильно понял, есть два основных подхода к созданию и запуску теста JUnit:

Подход A (стиль JUnit 3): создайте класс, расширяющий TestCase, и запустите методы тестирования со словом test, При запуске класса в качестве теста JUnit (в Eclipse) все методы начинаются со слова test автоматически запускаются.

import junit.framework.TestCase;

public class DummyTestA extends TestCase {

    public void testSum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

Подход B (стиль JUnit 4): создайте "нормальный" класс и добавьте @Test аннотация к методу. Обратите внимание, что вам не нужно начинать метод со слова test,

import org.junit.*;
import static org.junit.Assert.*;

public class DummyTestB {

    @Test
    public void Sum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

Смешение этих двух не является хорошей идеей, см., Например, этот вопрос stackru:

Теперь мои вопросы:

  1. Какой предпочтительный подход, или когда вы бы использовали один вместо другого?
  2. Подход B позволяет тестировать исключения, расширяя аннотацию @Test, как в @Test(expected = ArithmeticException.class), Но как вы проверяете исключения при использовании подхода А?
  3. При использовании подхода A вы можете сгруппировать несколько классов тестов в набор тестов следующим образом:

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    Но это не может быть использовано с подходом B (поскольку каждый тестовый класс должен быть подклассом TestCase). Как правильно группировать тесты для подхода B?

Изменить: я добавил версии JUnit для обоих подходов

5 ответов

Решение

Различие довольно простое:

  • простирающийся TestCase способ написания модульных тестов в JUnit 3 (конечно, он все еще поддерживается в JUnit 4)
  • с использованием @Test аннотация - способ, представленный JUnit 4

Как правило, вы должны выбирать путь аннотации, если только не требуется совместимость с JUnit 3 (и / или версией Java более ранней, чем Java 5). Новый способ имеет несколько преимуществ:

  • @Test annotaton более явный и его легче поддерживать в инструментах (например, таким образом легко найти все тесты)
  • Несколько методов могут быть аннотированы @Before / @BeforeClassа также @After / @AfterClass обеспечение большей гибкости
  • Поддержка для @Rule аннотации на такие вещи, как ExpectedException
  • Поддержка для @Ignored аннотирование
  • Поддержка альтернативных тестовых бегунов, использующих @RunWith

Чтобы проверить ожидаемые исключения в JUnit 3 TestCase Вы должны сделать текст явным.

public void testMyException() {
  try {
    objectUnderTest.myMethod(EVIL_ARGUMENT);
    fail("myMethod did not throw an Exception!");
  } catch (MyException e) {
    // ok!
    // check for properties of exception here, if desired
  }
}

У меня есть предпочтение JUnit 4 (аннотированный подход), потому что я считаю его более гибким.

Если вы хотите собрать набор тестов в JUnit 4, вы должны создать класс, объединяющий все тесты, подобные этому:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class)
@SuiteClasses({
    Test1.class,
    Test2.class,
    Test3.class,
    Test4.class
})public class TestSuite
{
 /* empty class */
}

В вашем вопросе есть неотвеченная часть, а именно: "Как правильно группировать тесты для подхода B"?

Официальный ответ заключается в том, что вы аннотируете класс с помощью @RunWith(Suite.class), а затем используете аннотацию @Suite.SuiteClasses для вывода списка классов. Вот как это делают разработчики JUnit (перечисляя каждый класс в наборе вручную). Во многих отношениях этот подход является улучшением в том смысле, что его тривиально и интуитивно понятно добавить до поведения пакета и после пакета (просто добавьте методы @BeforeClass и @AfterClass в класс, аннотированный @RunWith - гораздо лучше, чем старая TestFixture).).

Тем не менее, он имеет шаг назад, поскольку аннотации не позволяют динамически создавать список классов, и решение этой проблемы становится немного уродливым. Вы должны создать подкласс класса Suite и динамически создать массив классов в подклассе и передать его конструктору Suite, но это неполное решение в том смысле, что другие подклассы Suite (такие как Categories) не работают с ним и по существу не поддерживают динамический набор классов Test.

Вы должны использовать JUnit 4. Это лучше.

Многие фреймворки начали осуждать поддержку JUnit 3.8.

Это из справочной документации по Spring 3.0:

[Предупреждение] Устаревшая иерархия классов JUnit 3.8 устарела

В общем, вы всегда должны пытаться использовать последнюю стабильную версию фреймворка, когда запускаете что-то новое.

  1. "Предпочтительным" подходом будет использование аннотаций, которые были введены начиная с Junit 4. Они облегчают многие вещи (см. Ваш второй вопрос)

  2. Вы можете использовать простой блок try/catch для этого:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
Другие вопросы по тегам