setUp / tearDown (@Before / @After) зачем они нам нужны в JUnit?

Я считаю, что мы все знаем, что setUp (@Before) будет выполняться до любого метода тестирования и tearDown(@After) будет выполняться после метода тестирования.

также мы знаем, что Junit создаст один экземпляр Test на метод испытания.

мой вопрос в том, что мы можем просто переместить содержимое метода установки в конструктор класса и удалить метод установки? есть ли какая-либо конкретная причина сохранить метод установки?

6 ответов


этот (старый) лучшие практики JUnit статья ставит это так:

не используйте конструктор тестового набора для настройки тестового набора

настройка тестового набора в конструктор-не очень хорошая идея. Подумайте:

public class SomeTest extends TestCase
   public SomeTest (String testName) {
      super (testName);
      // Perform test set-up
   }
}

представьте, что во время выполнения установки код установки выдает IllegalStateException. В ответ, В JUnit будет бросить AssertionFailedError, указывая, что тестовый случай не может быть создать экземпляр. Вот пример результирующая трассировка стека:

junit.framework.AssertionFailedError: Cannot instantiate test case: test1   
    at junit.framework.Assert.fail(Assert.java:143)
    at junit.framework.TestSuite.runTest(TestSuite.java:178)
    at junit.framework.TestCase.runBare(TestCase.java:129)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.run(TestSuite.java, Compiled Code)
    at junit.ui.TestRunner2.run(TestRunner.java:429)

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

вместо настройки данных в конструктор, выполняет установку теста мимо переопределение setUp(). Любое исключение брошенный в пределах это правильно. Сравнить трассировку стека с предыдущим примером:

java.lang.IllegalStateException: Oops
    at bp.DTC.setUp(DTC.java:34) 
    at junit.framework.TestCase.runBare(TestCase.java:127)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    ...

эта трассировка стека намного больше информативный; он показывает, какое исключение был брошен (IllegalStateException) и откуда. Это делает его намного проще чтобы объяснить сбой тестовой установки.


на работе мы обнаружили кое-что интересное, что отвечает на ваш вопрос. Когда вы запускаете набор тестов, особенно большой набор тестов (200+) JUnit начинает использовать много памяти, это связано с тем, что все тесты создаются перед запуском любого фактического метода тестирования.

мы столкнулись с "утечкой памяти" из-за этого, потому что мы использовали пружину для подключения некоторых объектов JPA EntiryManager для наших тестов базы данных, это стало много объектов и много памяти и примерно на полпути через тесты мы получали исключения из памяти.

IMHO, лучшая практика-использовать setUp и tearDown для ввода ваших зависимостей и обнуления любых ссылок на классы, это заставит ваши тесты работать быстрее и избавит вас от головной боли!

надеюсь, вы узнаете из наших ошибок:)


вот 3 веские причины, почему. В заключение:

  1. некоторые ситуации могут предпочесть отложить настройку тестовых светильников как можно дольше, чтобы перед тест выполняет.

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

  3. вы получаете лучшую диагностику если код установки не выполняется в setUp (), а не в конструкторе.

1. Отложить настройку приспособления до теста

дизайн для удобства использования
http://www.artima.com/weblogs/viewpost.jsp?thread=70189

... И, как выразился Эллиот расти Гарольд, если вы собираетесь создать новый экземпляр TestCase для каждого метода тестирования, " какого черта беспокоиться о методе setUp ()?" вы можете просто используйте конструктор теста.

Я слышал, как Брюс Экель указал, что есть большая разница между созданием вашего приспособления в setUp() и созданием его в конструкторе TestCase. В JUnit создает все экземпляры TestCase спереди и затем для каждого экземпляра вызывает setup (), метод теста и tearDown (). Другими словами,тонкое различие заключается в том, что все конструкторы вызываются в пакетном режиме front, тогда как метод setUp () вызывается непосредственно перед каждым методом тестирования. Но это, кажется, не такая уж полезная разница на практике.

2. Отложить настройку приспособления только после всех тестов создаются

экстремальное Программирование JAVA ETutorial - 4.6 настройка и разрыв Down
http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

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

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

3. Лучшая диагностика в случае установки неудача

лучшие практики JUnit (JavaWorld)
http://www.javaworld.com/jw-12-2000/jw-1221-junit.html

настройка тестового набора в конструкторе не является хорошей идеей. ...

представьте себе [в коде, где выполняется настройка в конструкторе тестового набора], что при выполнении установки код установки создает исключение IllegalStateException. В ответ JUnit выдаст AssertionFailedError, указав, что тестовый случай может не инстанцируется. ...

эта трассировка стека [исключения, созданного в коде установки в конструкторе тестового набора] оказывается довольно неинформативной; она указывает только на то, что не удалось создать экземпляр тестового набора.

вместо настройки данных в конструкторе, выполните настройку теста, переопределив setUp (). Любое исключение, вызванное в setUp (), сообщается правильно. ...

этот трассировка стека [исключения, созданного в методе setUp () вместо конструктора тестового случая] гораздо более информативна; она показывает, какое исключение было создано (IllegalStateException) и откуда. Это значительно упрощает объяснение сбоя тестовой установки.


пользовательский бегун, такой как SpringJUnit4ClassRunner может потребоваться запустить некоторые коды между конструктором и @Before метод. В этом случае бегун может ввести некоторую зависимость, которая @Before методы нужны. Но инъекция зависимостей может быть запущена только после создания объекта.


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

предположим, что ваш тестовый класс обертывает, скажем, доступ к базе данных. После каждого теста вы хотите удалить все изменения, внесенные вашими тестами в БД - если вы этого не сделали, каждый тест выполняется с немного измененной базой данных. Кроме того, любой тест может увидеть другой набор изменений, если некоторые из предыдущих тестов завершились неудачей. Например, предположим, что test1 выполняет вставку, test2 проверяет, что вы точно читаете размер таблицы. День 1, test1 терпит неудачу, и 0 правильно. День 2, test1 успешно, и 1 Правильно?

BTW, junit также поддерживает @BeforeClass Если вы хотите выполнить глобальную настройку, а настройка и демонтаж являются необязательными.


Я думаю, почему бы следующие:

  1. Если вы перемещаете @Before contents в конструктор, это нормально, но содержимое @After, где вы можете перемещаться?
  2. различия конструктора и @Before/@After заключается в том, что конструктор должен использоваться для экземпляра некоторых для класса, @Before / @After-для подготовки ресурсов тестового случая.