JUnit всегда создает один экземпляр тестового класса для каждого метода @Test. Это фундаментальное дизайнерское решение, упрощающее написание тестов без побочных эффектов. Хорошие тесты не имеют зависимости от порядка выполнения (см. FIRST ), и создание новых экземпляров тестового класса и его переменных экземпляра для каждого теста имеет решающее значение для достижения этой цели. Некоторые среды тестирования повторно используют один и тот же экземпляр класса тестирования для всех тестов, что увеличивает вероятность случайного создания побочных эффектов между тестами.
И поскольку каждый тестовый метод имеет свой собственный экземпляр, нет смысла использовать методы @ BeforeClass / @ AfterClass в качестве методов экземпляра. В противном случае, для какого из экземпляров тестового класса следует вызывать методы? Если бы методы @ BeforeClass / @ AfterClass могли ссылаться на переменные экземпляра, тогда только один из методов @Test имел бы доступ к тем же самым переменным экземпляра - остальные имели бы переменные экземпляра в их значениях по умолчанию - и @ Метод тестирования будет выбран случайным образом, поскольку порядок методов в файле .class не указан / зависит от компилятора (IIRC, API отражения Java возвращает методы в том же порядке, в каком они объявлены в файле .class, хотя также это поведение не указано - я написал библиотеку для фактической сортировки их по номерам строк).
Так что принудительное использование статических методов - единственное разумное решение.
Вот пример:
public class ExampleTest {
@BeforeClass
public static void beforeClass() {
System.out.println("beforeClass");
}
@AfterClass
public static void afterClass() {
System.out.println("afterClass");
}
@Before
public void before() {
System.out.println(this + "\tbefore");
}
@After
public void after() {
System.out.println(this + "\tafter");
}
@Test
public void test1() {
System.out.println(this + "\ttest1");
}
@Test
public void test2() {
System.out.println(this + "\ttest2");
}
@Test
public void test3() {
System.out.println(this + "\ttest3");
}
}
Какие отпечатки:
beforeClass
ExampleTest@3358fd70 before
ExampleTest@3358fd70 test1
ExampleTest@3358fd70 after
ExampleTest@6293068a before
ExampleTest@6293068a test2
ExampleTest@6293068a after
ExampleTest@22928095 before
ExampleTest@22928095 test3
ExampleTest@22928095 after
afterClass
Как видите, каждый из тестов выполняется с собственным экземпляром. Что делает JUnit, в основном то же самое:
ExampleTest.beforeClass();
ExampleTest t1 = new ExampleTest();
t1.before();
t1.test1();
t1.after();
ExampleTest t2 = new ExampleTest();
t2.before();
t2.test2();
t2.after();
ExampleTest t3 = new ExampleTest();
t3.before();
t3.test3();
t3.after();
ExampleTest.afterClass();
Короткий ответ таков: нет веских причин для статичности.
Фактически, его статичность вызывает всевозможные проблемы, если вы используете Junit для выполнения интеграционных тестов DAO на основе DBUnit. Статическое требование мешает внедрению зависимостей, доступу к контексту приложения, обработке ресурсов, ведению журнала и всему, что зависит от "getClass".
источник
@PostConstruct
для настройки и@AfterClass
удаления, а статические из Junit я вообще игнорирую. Затем для тестов DAO я написал свой собственныйTestCaseDataLoader
класс, который вызываю из этих методов.@PostConstruct
и@AfterClass
просто ведет себя так же, как@Before
и@After
. Фактически, ваши методы будут вызываться для каждого тестового метода, а не один раз для всего класса (как утверждает Эско Луонтола в своем ответе, экземпляр класса создается для каждого тестового метода). Я не вижу полезности вашего решения, поэтому (если я что-то не пропущу)Документация JUnit кажется скудной, но я предполагаю: возможно, JUnit создает новый экземпляр вашего тестового класса перед запуском каждого тестового примера, поэтому единственный способ сохранить состояние вашего «приспособления» во время выполнения - сделать его статическим, что может принудительно, убедившись, что ваш fixtureSetup (метод @BeforeClass) является статическим.
источник
Хотя это не ответит на исходный вопрос. Это ответит на очевидное продолжение. Как создать правило, которое работает до и после занятия, до и после теста.
Для этого вы можете использовать этот шаблон:
До (Класс) JPAConnection создает соединение один раз, после того, как (Класс) закрывает его.
getEntityManger
возвращает внутренний класс,JPAConnection
который реализует EntityManager jpa и может получить доступ к соединению внутриjpaConnection
. До (тест) он начинает транзакцию, после (тест) откатывает ее снова.Это не является потокобезопасным, но может быть сделано так.
Выбранный код
JPAConnection.class
источник
Кажется, что JUnit создает новый экземпляр тестового класса для каждого тестового метода. Попробуйте этот код
На выходе 0 0 0
Это означает, что если метод @BeforeClass не является статическим, его нужно будет выполнять перед каждым тестовым методом, и не будет возможности различать семантику @Before и @BeforeClass.
источник
есть два типа аннотаций:
поэтому @BeforeClass должен быть объявлен статическим, потому что он вызывается один раз. Вы также должны учитывать, что статичность - это единственный способ гарантировать правильное распространение «состояния» между тестами (модель JUnit требует одного тестового экземпляра для каждого @Test) и, поскольку в Java только статические методы могут получить доступ к статическим данным ... @BeforeClass и @ AfterClass можно применять только к статическим методам.
Этот пример теста должен прояснить использование @BeforeClass и @Before:
вывод:
источник
Согласно JUnit 5, кажется, что философия строгого создания нового экземпляра для каждого метода тестирования была несколько ослаблена. Они добавили аннотацию , которая создает экземпляр тестового класса только один раз. Таким образом, эта аннотация также позволяет методам, аннотированным @ BeforeAll / @ AfterAll (замена @ BeforeClass / @ AfterClass), быть нестатическими. Итак, тестовый класс вроде этого:
напечатает:
Таким образом, вы можете создавать экземпляры объектов один раз для каждого тестового класса. Конечно, вы сами обязаны избегать мутации объектов, которые создаются таким образом.
источник
Чтобы решить эту проблему, просто измените метод
к
и все, что определено в этом методе
static
.источник