@BeforeClass e herança - Ordem de execução
-
22-09-2019 - |
Pergunta
Eu tenho uma classe base abstrata, que uso como base para meus testes de unidade (Testng 5.10). Nesta aula, inicializo todo o ambiente para meus testes, configurando mapeamentos de banco de dados, etc. Esta classe abstrata tem um método com um @BeforeClass
anotação que faz a inicialização.
Em seguida, estendo a aula com classes específicas em que tenho @Test
métodos e também @BeforeClass
métodos. Esses métodos fazem a inicialização específica da classe do ambiente (por exemplo, coloca alguns registros no banco de dados).
Como posso fazer cumprir uma ordem específica do @BeforeClass
Métodos anotados? Eu preciso que os da classe base abstrata sejam executados antes dos da classe prolongada.
Exemplo:
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@BeforeClass
doSpecificInitialization() {...}
@Test
doTests() {...}
}
Ordem esperada:
A.doInitialization
B.doSpecificInitialization
B.doTests
Ordem real:
B.doSpecificInitialization // <- crashes, as the base init is missing
(A.doInitialization // <---not executed
B.doTests) // <-/
Solução
Não coloque o @BeforeClass
no abstract
classe. Chame de cada subclasse.
abstract class A {
void doInitialization() {}
}
class B extends A {
@BeforeClass
void doSpecificInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
Parece que o testng tem @BeforeClass(dependsOnMethods={"doInitialization"})
- De uma chance.
Outras dicas
editar: Resposta abaixo é para Junit, mas vou deixar aqui de qualquer maneira, porque pode ser útil.
De acordo com Junit API: "Os métodos @BeFeClass de superclasses serão executados antes daqueles que a classe atual".
Eu testei isso, e parece funcionar para mim.
No entanto, como @odys menciona abaixo, para Junit, você precisa ter o Dois métodos nomeados de maneira diferente embora, como fazer o contrário, resulte apenas o método da subclasse sendo executado porque o pai será sombreado.
Eu adicionei public
para a classe abstrata e testng (6.0.1) executaram a doinitialização () antes doTests
. Testng não executa doInitialization()
Se eu remover public
da classe A.
public abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Test
doTests() {...}
}
Acabei de experimentar o seu exemplo com o 5.11 e recebo o @BeForEClass da classe base invocada primeiro.
Você pode postar seu arquivo testng.xml? Talvez você esteja especificando A e B lá, enquanto apenas B é necessário.
Sinta-se à vontade para acompanhar a lista de correspondência dos usuários de teste e podemos examinar mais de perto o seu problema.
- Cedric
Acabei de passar por isso e encontrei mais uma maneira de conseguir isso. Apenas use alwaysRun
sobre @BeforeClass
ou @BeforeMethod
Na classe abstrata, funciona como seria de esperar.
public class AbstractTestClass {
@BeforeClass(alwaysRun = true)
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
}
Quando eu corro de: Junitcore.runclasses (testclass.class);Ele executará o pai corretamente, antes da criança (você não precisa super.setupBeFeClass ();) Se você o executar do Eclipse: por algum motivo, ele não executa a classe base. O trabalho por aí: ligue explícito na classe base: (Bastest.setupBeforeClass ();) Você pode querer ter um sinalizador na classe base, caso o execute a partir de um aplicativo, para determinar se ele já está configurado ou não. Portanto, ele é executado apenas uma vez se você o executar através de ambos os métodos possíveis (como do Eclipse para testes pessoais e através da Ant para uma versão de compilação).
Isso parece ser um bug do eclipse, ou pelo menos resultados inesperados.
Para Junit: Como @fortaga mencionou: De acordo com a API JUNIT: "Os métodos @BeFeClass de superclasses serão executados antes daqueles que a classe atual".
Mas tenha cuidado não para citar os dois métodos com o mesmo nome. Como neste caso, o método pai será oculto pelos pais da criança. Fonte.
Que tal ter seu método @beforeClass chamar um método vazio de especificeforeClass () que pode ou não ser sobrescrito por sub -classes como assim:
public class AbstractTestClass {
@BeforeClass
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
protected void specificBeforeClass() {}
}
public class SpecificTest {
@Override
protected void specificBeforeClass() {
// Do specific stuff
}
// Tests
}
dependsOnMethod
pode ser usado.
por exemplo, em caso de primavera (AbstractTestNGSpringContextTests
)
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Verifique sua declaração de importação. Deveria ser
import org.testng.annotations.BeforeClass;
não
import org.junit.BeforeClass;
Por que você não tenta criar um método abstrato DosPeCialinit () em sua super classe, chamado do seu método anotado no BeforeClass na Superclass.
Portanto, os desenvolvedores herdando sua classe são forçados a implementar esse método.
Há outra solução fácil aqui.
Minha situação específica é que preciso injetar serviços simulados de "beforeClass" na subclasse antes "beforeClass" na superclasse é executado.
Para fazer isso - basta usar um @ClassRule
na subclasse.
Por exemplo:
@ClassRule
public static ExternalResource mocksInjector = new ExternalResource() {
@Override
protected void before() {
// inject my mock services here
// Note: this is executed before the parent class @BeforeClass
}
};
Eu espero que isso ajude. Isso pode efetivamente executar a configuração estática na ordem "reversa".
Eu enfrentei um problema semelhante hoje, a única diferença foi uma classe base não era abstrata
Aqui está o meu caso
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
private void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
Ocorreu que um @BeforeClass
O método da classe A nunca foi executado.
- A.Doinitialization () -> Isso nunca foi executado silenciosamente
- B. Dosespecificinitialização ()
- B.DOTESTS ()
Brincando com modificadores de privacidade, encontrei que testng não será executado uma @BeforeClass
Método anotado de classe herdada Se um método não for visível de um infectorado de classe
Então isso vai funcionar:
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
//Here a privacy modifier matters -> please make sure your method is public or protected so it will be visible for ancestors
protected void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
Como resultado, acontece:
- A.Doinitialization ()
- B. Dosespecificinitialização ()
- B.DOTESTS ()
Isso funciona para mim -
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Override
@BeforeClass
doInitialization() {
//do class specific init
}
@Test
doTests() {...}
}
No meu caso (JUNIT), tenho os mesmos métodos chamados setup () na classe base e na classe derivada. Nesse caso só O método da classe derivada é chamado, e eu o chamo de método de classe base.
Uma maneira melhor e mais limpa de conseguir isso usando a herança pode ser como seguinte -
abstract class A {
@BeforeClass
void doInitialization() {}
}
class B extends A {
@Override
@BeforeClass
void doInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}