JUnit sempre cria uma instância da classe de teste para cada método @Test. Esta é uma decisão de design fundamental para tornar mais fácil escrever testes sem efeitos colaterais. Bons testes não têm dependências de ordem de execução (consulte FIRST ) e criar novas instâncias da classe de teste e suas variáveis de instância para cada teste é crucial para conseguir isso. Algumas estruturas de teste reutilizam a mesma instância de classe de teste para todos os testes, o que leva a mais possibilidades de criar acidentalmente efeitos colaterais entre os testes.
E como cada método de teste tem sua própria instância, não faz sentido que os métodos @ BeforeClass / @ AfterClass sejam métodos de instância. Caso contrário, em qual das instâncias da classe de teste os métodos devem ser chamados? Se fosse possível para os métodos @ BeforeClass / @ AfterClass referenciarem variáveis de instância, então apenas um dos métodos @Test teria acesso a essas mesmas variáveis de instância - o resto teria as variáveis de instância em seus valores padrão - e o @ O método de teste seria selecionado aleatoriamente, porque a ordem dos métodos no arquivo .class não é especificada / dependente do compilador (IIRC, a API de reflexão do Java retorna os métodos na mesma ordem em que são declarados no arquivo .class, embora também esse comportamento não é especificado - eu escrevi uma biblioteca para realmente classificá-las por seus números de linha).
Portanto, impor que esses métodos sejam estáticos é a única solução razoável.
Aqui está um exemplo:
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");
}
}
Quais impressões:
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
Como você pode ver, cada um dos testes é executado com sua própria instância. O que o JUnit faz é basicamente o mesmo:
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();
A resposta curta é esta: não há um bom motivo para ser estático.
Na verdade, torná-lo estático causa todos os tipos de problemas se você usar o Junit para executar testes de integração DAO baseados em DBUnit. O requisito estático interfere na injeção de dependência, acesso ao contexto do aplicativo, manipulação de recursos, registro e qualquer coisa que dependa de "getClass".
fonte
@PostConstruct
para configurar e@AfterClass
derrubar, e ignoro as anotações estáticas do Junit. Para os testes DAO, escrevi minha própriaTestCaseDataLoader
classe, que invoco a partir desses métodos.@PostConstruct
e@AfterClass
apenas se comporta da mesma forma que@Before
e@After
. Na verdade, seus métodos serão chamados para cada método de teste e não uma vez para a classe inteira (como Esko Luontola afirma em sua resposta, uma instância de classe é criada para cada método de teste). Não consigo ver a utilidade da sua solução, então (a menos que eu perca algo)A documentação do JUnit parece escassa, mas suponho: talvez o JUnit crie uma nova instância de sua classe de teste antes de executar cada caso de teste, então a única maneira de seu estado de "fixação" persistir entre as execuções é torná-lo estático, o que pode ser reforçado certificando-se de que seu fixtureSetup (método @BeforeClass) é estático.
fonte
Embora isso não responda à pergunta original. Ele responderá ao acompanhamento óbvio. Como criar uma regra que funcione antes e depois de uma aula e antes e depois de um teste.
Para conseguir isso, você pode usar este padrão:
Em before (Class), o JPAConnection cria a conexão uma vez depois de (Class) ele a fecha.
getEntityManger
retorna uma classe internaJPAConnection
que implementa o EntityManager do jpa e pode acessar a conexão dentro dojpaConnection
. Em antes (teste), ele começa uma transação após (teste) ele faz o rollback novamente.Isso não é thread-safe, mas pode ser feito para ser assim.
Código selecionado de
JPAConnection.class
fonte
Parece que o JUnit cria uma nova instância da classe de teste para cada método de teste. Experimente este código
A saída é 0 0 0
Isso significa que se o método @BeforeClass não for estático, ele deverá ser executado antes de cada método de teste e não haverá como diferenciar entre a semântica de @Before e @BeforeClass
fonte
existem dois tipos de anotações:
portanto, @BeforeClass deve ser declarado estático porque é chamado uma vez. Você também deve considerar que ser estático é a única maneira de garantir a propagação de "estado" adequada entre os testes (o modelo JUnit impõe uma instância de teste por @Test) e, uma vez que em Java apenas métodos estáticos podem acessar dados estáticos ... @BeforeClass e @ AfterClass pode ser aplicado apenas a métodos estáticos.
Este exemplo de teste deve esclarecer o uso de @BeforeClass vs @Before:
resultado:
fonte
De acordo com o JUnit 5, parece que a filosofia de criar estritamente uma nova instância por método de teste foi um pouco afrouxada. Eles adicionaram uma anotação que irá instanciar uma classe de teste apenas uma vez. Esta anotação, portanto, também permite que os métodos anotados com @ BeforeAll / @ AfterAll (as substituições para @ BeforeClass / @ AfterClass) sejam não estáticos. Então, uma classe de teste como esta:
imprimiria:
Portanto, você pode realmente instanciar objetos uma vez por classe de teste. Claro, isso torna sua responsabilidade evitar a mutação de objetos que são instanciados dessa maneira.
fonte
Para resolver este problema, basta alterar o método
para
e todos os que são definidos neste método para
static
.fonte