Estou tentando configurar e desmontar um conjunto de testes de integração, usando o jUnit 4.4 para executar os testes. A desmontagem deve ser executada de forma confiável. Estou tendo outros problemas com o TestNG, por isso estou tentando fazer a portabilidade de volta para o jUnit. Quais ganchos estão disponíveis para execução antes que qualquer teste seja executado e depois que todos os testes forem concluídos?
Nota: estamos usando o maven 2 para nossa construção. Eu tentei usar as pre-
& post-integration-test
fases do maven , mas, se um teste falhar, o maven para e não executa post-integration-test
, o que não ajuda em nada.
java
testing
junit
integration-testing
sblundy
fonte
fonte
post-integration-test
se um teste falhar. Veja também esta página wiki .Respostas:
Sim, é possível executar métodos de configuração e desmontagem de maneira confiável antes e depois de qualquer teste em uma suíte de teste. Deixe-me demonstrar em código:
package com.test; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({Test1.class, Test2.class}) public class TestSuite { @BeforeClass public static void setUp() { System.out.println("setting up"); } @AfterClass public static void tearDown() { System.out.println("tearing down"); } }
Portanto, sua
Test1
classe seria algo como:package com.test; import org.junit.Test; public class Test1 { @Test public void test1() { System.out.println("test1"); } }
... e você pode imaginar que
Test2
é semelhante. Se você corresseTestSuite
, obteria:Portanto, você pode ver que a configuração / desmontagem só é executada antes e depois de todos os testes, respectivamente.
O problema: isso só funciona se você estiver executando o conjunto de testes e não executando Test1 e Test2 como testes JUnit individuais. Você mencionou que está usando o maven, e o plug-in surefire do maven gosta de executar testes individualmente, e não como parte de um pacote. Nesse caso, eu recomendaria criar uma superclasse que cada classe de teste estende. A superclasse então contém os métodos @BeforeClass e @AfterClass anotados. Embora não seja tão limpo quanto o método acima, acho que funcionará para você.
Quanto ao problema com testes com falha, você pode definir maven.test.error.ignore para que a construção continue nos testes que falharam. Isso não é recomendado como uma prática contínua, mas deve fazer você funcionar até que todos os seus testes sejam aprovados. Para obter mais detalhes, consulte a documentação infalível do maven .
fonte
Um colega meu sugeriu o seguinte: você pode usar um RunListener personalizado e implementar o método testRunFinished (): http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org. junit.runner.Result)
Para registrar o RunListener, basta configurar o plugin surefire da seguinte forma: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html seção "Usando ouvintes e repórteres personalizados"
Esta configuração também deve ser escolhida pelo plugin à prova de falhas. Esta solução é ótima porque você não precisa especificar Suites, classes de teste de pesquisa ou qualquer uma dessas coisas - ela permite que o Maven faça sua mágica, esperando que todos os testes terminem.
fonte
Você pode usar a anotação @ClassRule no JUnit 4.9+ conforme descrevi em uma resposta a outra pergunta .
fonte
Usando anotações, você pode fazer algo assim:
import org.junit.*; import static org.junit.Assert.*; import java.util.*; class SomethingUnitTest { @BeforeClass public static void runBeforeClass() { } @AfterClass public static void runAfterClass() { } @Before public void setUp() { } @After public void tearDown() { } @Test public void testSomethingOrOther() { } }
fonte
Aqui nós
fonte
Quanto a "Nota: estamos usando o maven 2 para nossa construção. Eu tentei usar as fases de teste pré e pós-integração do maven, mas, se um teste falhar, o maven para e não executa o teste pós-integração , o que não ajuda em nada. "
você pode tentar o plug-in à prova de falhas, acho que ele tem a facilidade de garantir que a limpeza ocorra independentemente da configuração ou do status do estágio intermediário
fonte
Desde que todos os seus testes possam estender uma aula "técnica" e estejam no mesmo pacote, você pode fazer um pequeno truque:
public class AbstractTest { private static int nbTests = listClassesIn(<package>).size(); private static int curTest = 0; @BeforeClass public static void incCurTest() { curTest++; } @AfterClass public static void closeTestSuite() { if (curTest == nbTests) { /*cleaning*/ } } } public class Test1 extends AbstractTest { @Test public void check() {} } public class Test2 extends AbstractTest { @Test public void check() {} }
Esteja ciente de que esta solução tem muitas desvantagens:
Para obter informações: listClassesIn () => Como você encontra todas as subclasses de uma determinada classe em Java?
fonte
Pelo que eu sei, não há mecanismo para fazer isso no JUnit, no entanto, você pode tentar criar uma subclasse de Suite e substituir o método run () por uma versão que forneça ganchos.
fonte
Uma vez que o maven-surefire-plugin não executa a classe Suite primeiro, mas trata as classes suite e de teste da mesma forma, podemos configurar o plugin como abaixo para habilitar apenas as classes suite e desabilitar todos os testes. O Suite executará todos os testes.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> <includes> <include>**/*Suite.java</include> </includes> <excludes> <exclude>**/*Test.java</exclude> <exclude>**/*Tests.java</exclude> </excludes> </configuration> </plugin>
fonte
A única maneira de obter a funcionalidade que você deseja seria fazer algo como
import junit.framework.Test; import junit.framework.TestResult; import junit.framework.TestSuite; public class AllTests { public static Test suite() { TestSuite suite = new TestSuite("TestEverything"); //$JUnit-BEGIN$ suite.addTestSuite(TestOne.class); suite.addTestSuite(TestTwo.class); suite.addTestSuite(TestThree.class); //$JUnit-END$ } public static void main(String[] args) { AllTests test = new AllTests(); Test testCase = test.suite(); TestResult result = new TestResult(); setUp(); testCase.run(result); tearDown(); } public void setUp() {} public void tearDown() {} }
Eu uso algo assim no eclipse, então não tenho certeza de quão portátil é fora desse ambiente
fonte
Se você não deseja criar um conjunto e precisa listar todas as suas classes de teste, pode usar a reflexão para encontrar o número de classes de teste dinamicamente e fazer uma contagem regressiva em uma classe base @AfterClass para fazer o tearDown apenas uma vez:
public class BaseTestClass { private static int testClassToRun = 0; // Counting the classes to run so that we can do the tear down only once static { try { Field field = ClassLoader.class.getDeclaredField("classes"); field.setAccessible(true); @SuppressWarnings({ "unchecked", "rawtypes" }) Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader()); for (Class<?> clazz : classes) { if (clazz.getName().endsWith("Test")) { testClassToRun++; } } } catch (Exception ignore) { } } // Setup that needs to be done only once static { // one time set up } @AfterClass public static void baseTearDown() throws Exception { if (--testClassToRun == 0) { // one time clean up } } }
Se você preferir usar @BeforeClass em vez dos blocos estáticos, também pode usar um sinalizador booleano para fazer a contagem de reflexão e testar a configuração apenas uma vez na primeira chamada. Espero que isso ajude alguém, levei uma tarde para descobrir uma maneira melhor do que enumerar todas as classes em uma suíte.
Agora, tudo que você precisa fazer é estender essa classe para todas as suas classes de teste. Já tínhamos uma classe base para fornecer algumas coisas comuns para todos os nossos testes, então essa foi a melhor solução para nós.
A inspiração vem desta resposta SO https://stackoverflow.com/a/37488620/5930242
Se você não quiser estender essa classe a todos os lugares, esta última resposta do SO pode fazer o que você quiser.
fonte