JUnit: использование конструктора вместо @Before - PullRequest
64 голосов
/ 23 мая 2011

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

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

Ответы [ 9 ]

76 голосов
/ 23 мая 2011

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

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

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

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

  • @Before позволяет переопределять поведение родительского класса, конструкторы заставляют вас вызывать конструкторы родительского класса
  • Конструктор запускает до конструкторов подкласса и @Rule методов, @Before запускает после всех этих
  • Исключения во время @Before вызывают @After методы для вызова, Исключения в конструкторе не
26 голосов
/ 10 сентября 2012

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

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

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

@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));
    }
}
7 голосов
/ 03 октября 2014

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

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

5 голосов
/ 11 августа 2011

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

1 голос
/ 14 января 2019

Цитата из http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

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

В тех случаях, когда ваш тестовый пример является частью более глубокой иерархии наследования, вы можете отложить инициализацию объекта доэкземпляры производных классов полностью построены.Это хорошая техническая причина, почему вы можете использовать setUp () вместо конструктора для инициализации.Использование setUp () и tearDown () также полезно для документирования, просто потому, что оно может облегчить чтение кода.

1 голос
/ 27 декабря 2017

Есть одна вещь, которую конструктор может архивировать, но не @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
   } 
}
1 голос
/ 23 мая 2011

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

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

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

0 голосов
/ 20 ноября 2016

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

public class TestClass {

    @Rule
    public SomeRule rule;

    public TestClass() {
        // code to initialize the rule field
        conf = new RuleConf()
        rule = new SomeRule(conf)
    }
}
0 голосов
/ 23 мая 2011

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

...