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


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

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

8 57

8 ответов:

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

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

заметные различия

Подробнее из комментариев:

  • @Before позволяет переопределять поведение родительского класса, конструкторы заставляют вас вызывать конструкторы родительского класса
  • конструктор работает до конструкторы подклассов и @Rule методы @Before работает после все
  • исключения в @Before причина @After вызываемые методы, исключения в конструкторе не

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

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

вот пример (правда надуманный) пример:

@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));
    }
}

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

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

ИМХО, @Before нарушает одно из самых важных соглашений Java, которое полагается на конструктор для полной инициализации объектов!

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

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

см.:http://junit.sourceforge.net/javadoc/org/junit/Before.html

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

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

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
   } 
}

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

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

public class TestClass {

    @Rule
    public SomeRule rule;

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