JUnit: использование конструктора вместо @Before

Я использую JUnit 4. Я не вижу разницы между инициализацией в конструкторе или использованием выделенной функции init, аннотированной @Before. Означает ли это, что мне не нужно беспокоиться об этом?

Есть ли случай, когда @Before дает больше, чем просто инициализацию в конструкторе?

Ответ 1

Нет, использование конструктора для инициализации вашего тестового прибора JUnit технически равно методу @Before (из-за того, что JUnit создает новый экземпляр класса тестирования для каждого @Test). Единственное (коннотационное) различие заключается в том, что он нарушает симметрию между @Before и @After, что может быть запутанным для некоторых. ИМХО лучше придерживаться конвенций (использующих @Before).

Заметим также, что до JUnit 4 и аннотаций были выделены методы setUp() и tearDown() - аннотации @Before и @After заменяют их, но сохраняют основную логику. Таким образом, использование аннотаций также облегчает жизнь кому-то, мигрирующему из JUnit 3 или более ранних версий.

Ответ 2

@Прежде всего, имеет смысл использовать в некоторых случаях, потому что он получает имя ПОСЛЕ конструктора для класса. Эта разница важна, когда вы используете макетную структуру, такую ​​как Mockito с аннотациями @Mock, потому что ваш метод @Before будет вызываться после инициализации mocks. Затем вы можете использовать свои mocks для предоставления аргументов конструктора тестируемому классу.

Я считаю, что это очень распространенный образец в моих модульных тестах при использовании сотрудничества beans.

Вот пример (по общему признанию, надуманный):

@RunWith(MockitoJUnitRunner.class)
public class CalculatorTest {
    @Mock Adder adder;
    @Mock Subtractor subtractor;
    @Mock Divider divider;
    @Mock Multiplier multiplier;

    Calculator calculator;

    @Before
    public void setUp() {
        calculator = new Calculator(adder,subtractor,divider,multiplier);
    }

    @Test
    public void testAdd() {
        BigDecimal value = calculator.add(2,2);
        verify(adder).add(eq(2),eq(2));
    }
}

Ответ 3

Я предпочитаю объявлять свои фиксы как final и инициализировать их inline или в конструкторе, поэтому я не забываю их инициализировать! Однако, поскольку исключения, брошенные в @Before, обрабатываются более удобным для пользователя способом, я обычно инициализирую тестируемый объект в @Before.

Ответ 4

Я предпочитаю использовать конструкторы для инициализации моих тестовых объектов, потому что он позволяет мне сделать все члены final так, чтобы IDE или компилятор рассказывал мне, когда конструктор забыл инициализировать элемент и не позволяет другому методу их устанавливать.

IMHO, @Before нарушает одно из наиболее важных соглашений Java - полагаться на конструктор, чтобы полностью инициализировать объекты!

Ответ 5

@Before вызывается перед любым @Test не только один раз на тестовый класс.
Это можно использовать для данных reset/init для каждого конкретного теста (например, для сброса переменных в определенное значение и т.д.).

В той же моде @After можно использовать для очистки кода после выполнения метода @Test.

Смотрите: http://junit.sourceforge.net/javadoc/org/junit/Before.html

Ответ 6

@Before имеет смысл использовать по нескольким причинам. Это делает ваш тестовый код более удобочитаемым. Он соответствует аннотации @After, которая отвечает за освобождение используемых ресурсов и является аналогом аннотации @BeforeClass.

Ответ 7

Нет никакой разницы, кроме того, что конструктор является единственным методом, который может инициализировать объекты @Rule:

public class TestClass {

    @Rule
    public SomeRule rule;

    public TestClass() {
        // code to initialize the rule field
        conf = new RuleConf()
        rule = new SomeRule(conf)
    }
}

Ответ 8

Есть одна вещь, которую конструктор может архивировать, но не @Before.

Вы должны использовать конструктор, когда вам нужно задать начальные поля, определенные в родительском классе. Например:

abstract class AbstractIT {
   int fieldAssignedInSubClass;
   public AbstractIT(int fieldAssignedInSubClass) {
      this.fieldAssignedInSubClass= fieldAssignedInSubClass;
   }

   @Before
   void before() {
      // comsume fieldAssignedInSubClass
   } 
}

public class ChildIT extends AbstractIT{
   public ChildIT() {
      // assign fieldAssignedInSubClass by constructor
      super(5566); 
   }

   @Before
   void before() {
      // you cannot assign fieldAssignedInSubClass by a @Before method
   } 
}