Я использую 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
}
}