Tornando cada método de teste executado em sua própria instância de uma class de teste com TestNG?

Então eu pensei que o código a seguir seria executado corretamente no TestNG, embora não funcione:

public class Tests { int i = 0; @Test public void testA() { Assert.assertEquals(0, i); ++i; } @Test public void testB() { Assert.assertEquals(0, i); ++i; } } 

Existe uma maneira de fazer TestNG acionar uma nova class de testes para cada método de teste?

A solução comum é usar um método @BeforeMethod para configurar o estado de teste,

 @BeforeMethod public void setup() { i = 0; } 

De longe, a solução mais comum para este problema que eu encontrei é usar ThreadLocal e apenas lidar com o fato de que você só tem uma instância de cada class de teste. Isso lida com todas as questões sobre como lidar com testes paralelos / encadeados. Isso funciona, mas é um pouco feio.

 private ThreadLocal i = new ThreadLocal<>(); @BeforeMethod public void setup() { i.set(0); } @Test public void testA() { Integer i1 = i.get(); Assert.assertEquals(0, i.get().intValue()); i.set(i1 + 1); } @Test public void testB() { Integer i1 = i.get(); Assert.assertEquals(0, i.get().intValue()); i.set(i1 + 1); } 

Agora, de volta à raiz da sua pergunta, novas instâncias para cada método. Eu tenho pesquisado por algumas semanas tópicos semelhantes, e eu identifiquei que este é o número um problema que eu estava tendo pessoalmente com TestNG. Isso literalmente me deixou louco.

Se eu fosse ignorar o fato de que seus testes tinham um monte de complexidades, você poderia potencialmente trabalhar em conjunto para atender aos requisitos listados.

Um TestNG @Factory Factory permite que você crie novas instâncias de suas classs de teste.

 @Factory public Object[] factory(){ return new Object[]{new Tests(), new Tests()}; } 

Eu criei agora duas instâncias de Tests , para serem executadas pelo testNG

Então o problema é que seus testes ainda falham, porque ele tentará executar todos os methods de teste em suas classs de teste. Para contornar isso, você poderia implementar um IMethodInterceptor e hackear uma solução para garantir que cada instância do Testes só executasse um método. Mantenha uma lista de methods e passe por eles um de cada vez.

Aqui está um exemplo bruto que eu hackeei em conjunto.

 public class TestFactory implements IMethodInterceptor { private List methodsToRun = new ArrayList<>(); private List testInstances = new ArrayList<>(); @Factory public Object[] factory(){ return new Object[]{new Tests(), new Tests()}; } @Override public List intercept(List methods, ITestContext context) { ArrayList tempList = new ArrayList<>(); for(IMethodInstance i: methods){ if(testInstances.contains(i.getInstance())){ continue; } String mName = i.getMethod().getConstructorOrMethod().getName(); if(!methodsToRun.contains(mName)){ tempList.add(i); methodsToRun.add(mName); testInstances.add(i.getInstance()); } } return tempList; } } 

Em seguida, adicione seu ouvinte ao topo da sua class Tests

 @Listeners(TestFactory.class) 

Você pode melhorar isso criando dinamicamente novas instâncias dos testes na fábrica. Também quebrando o ouvinte em seu próprio arquivo e inúmeras outras melhorias, mas você começa a essência.

Talvez uma solução louca como a acima funcione para você ou para outra pessoa.