2009-12-02 15 views
23

Occasionalmente abbiamo bug che appaiono una volta in ogni esecuzione di X. Prima che le persone eseguano il check-in (dove è automaticamente JUnit'd), i nostri sviluppatori devono passare JUnit localmente tramite Eclipse.C'è un modo per far eseguire a Eclipse un test JUnit più volte fino al fallimento?

C'è qualche modo conveniente (Plugin integrato o di alta qualità) per fare in modo che Eclipse esegua lo stesso test X volte e si fermi in caso di errore? Un'alternativa al solo clic su Esegui X volte?

Nota che sto cercando qualcosa nell'interfaccia utente (ad esempio, fai clic con il pulsante destro del mouse e pronuncia "Esegui X volte" invece di "Esegui").

+0

Questo non è veramente rilevante per la tua domanda, ma la mia curiosità è piccata - che tipo di bug stanno comparendo solo ogni tanto corre? C'è qualche elemento casuale nei test? Più thread forse? Presumo che tu abbia già provato a eliminare la casualità in qualche modo. –

+1

Se usi Spring (o se gli sviluppatori possono aggiungere Spring in locale) puoi annotare i test con @Repeat (numero_di_runzioni). – laura

+0

@Peter: Principalmente cose come condizioni di gara e stati impuri. Stiamo testando una parte di un sistema contro una serie di servizi al di fuori del nostro controllo. – Uri

risposta

10

Se il ciclo for funziona, quindi sono d'accordo con i n.

Se è necessario ripetere l'intero setup-test-teardown, quindi è possibile utilizzare un TestSuite:

  1. pulsante destro del mouse sul pacchetto contenente il test di ripetere
  2. andare a New e scegliere di crea un test JUnit SUITE
  3. Assicurati che solo il test che vuoi ripetere sia selezionato e clicchi per finire.
  4. Modificare il file per eseguirlo più volte.

Nel file basta trovare la linea

addTestSuite(YourTestClass.class) 

, e avvolgere che in un ciclo for.

Sono abbastanza sicuro che è possibile utilizzare addTest anziché addTestSuite per ottenere l'esecuzione di un solo test da quella classe se si desidera ripetere un singolo metodo di prova.

+0

Sì, ho provato qualcosa di simile. Ma speravo in qualcosa direttamente nell'interfaccia utente. – Uri

+2

è una soluzione solo per Junit 3? –

+0

Non sarei sorpreso se fosse diverso in JUnit 4 (non l'ho provato). Ma l'idea di base è di lasciare che Eclipse faccia la prima istanza del test, e poi replichi quello che hanno fatto più volte, quindi penserei che ci sarebbe una soluzione equivalente di JUnit 4 –

1

Non credo che ci sia un modo per fare in modo che junit faccia esattamente quello che stai chiedendo.

Se più esecuzioni producono risultati diversi, è necessario eseguire un test dell'unità per verificare il caso. Quale potrebbe essere semplice come eseguire un ciclo for nei casi di test rilevanti.

+1

Sì, ma abbiamo un'intera suite di test in cui più persone continuano ad aggiungere test ... Sul server di build abbiamo un ciclo ... Speravo che Eclipse avesse qualcosa. – Uri

3

So che non risponde direttamente alla domanda, ma se un test non passa ogni volta che viene eseguito è un odore di prova noto come Erratic Test. Ci sono diverse cause possibili per questo (da xUnit test Patterns):

  • Test Interazione
  • Interacting prova Suites
  • sola prova
  • Resource dispersione
  • Ottimismo Resource
  • Irripetibile test
  • Test Run War
  • test non deterministiche

I dettagli di ciascuno di questi è documentata nel capitolo 16 di xUnit prova Patterns.

7

Se si vuole davvero eseguire una classe di test fino al fallimento, è necessario il proprio corridore.

@RunWith(RunUntilFailure.class) 
public class YourClass { 

    // .... 

} 

che potrebbero essere attuate nel modo seguente ...

package com.example; 

import org.junit.internal.runners.*; 
import org.junit.runner.notification.*; 
import org.junit.runner.*; 

public class RunUntilFailure extends Runner { 

    private TestClassRunner runner; 

    public RunUntilFailure(Class<?> klass) throws InitializationError { 
     this.runner = new TestClassRunner(klass); 
    } 

    @Override 
    public Description getDescription() { 
     Description description = Description.createSuiteDescription("Run until failure"); 
     description.addChild(runner.getDescription()); 
     return description; 
    } 

    @Override 
    public void run(RunNotifier notifier) { 
     class L extends RunListener { 
      boolean fail = false; 
      public void testFailure(Failure failure) throws Exception { fail = true; } 
     } 
     L listener = new L(); 
     notifier.addListener(listener); 
     while (!listener.fail) runner.run(notifier); 
    } 

} 

... rilasciando codice non testato, sentendo TDD colpa :)

3

Sulla base della risposta di @ akuhn, ecco cosa mi è venuto in mente - piuttosto che funzionare per sempre, questo verrà eseguito 50 volte o fino al fallimento, a seconda di cosa si verifica per primo.

package com.foo  

import org.junit.runner.Description; 
import org.junit.runner.Runner; 
import org.junit.runner.notification.Failure; 
import org.junit.runner.notification.RunListener; 
import org.junit.runner.notification.RunNotifier; 
import org.junit.runners.BlockJUnit4ClassRunner; 
import org.junit.runners.model.InitializationError; 

public class RunManyTimesUntilFailure extends Runner { 

    private static final int MAX_RUN_COUNT = 50; 

    private BlockJUnit4ClassRunner runner; 

    @SuppressWarnings("unchecked") 
    public RunManyTimesUntilFailure(final Class testClass) throws InitializationError { 
     runner = new BlockJUnit4ClassRunner(testClass); 
    } 

    @Override 
    public Description getDescription() { 
     final Description description = Description.createSuiteDescription("Run many times until failure"); 
     description.addChild(runner.getDescription()); 
     return description; 
    } 

    @Override 
    public void run(final RunNotifier notifier) { 
     class L extends RunListener { 
      boolean shouldContinue = true; 
      int runCount = 0; 

      @Override 
      public void testFailure(@SuppressWarnings("unused") final Failure failure) throws Exception { 
       shouldContinue = false; 
      } 

      @Override 
      public void testFinished(@SuppressWarnings("unused") Description description) throws Exception { 
       runCount++; 

       shouldContinue = (shouldContinue && runCount < MAX_RUN_COUNT); 
      } 
     } 

     final L listener = new L(); 
     notifier.addListener(listener); 

     while (listener.shouldContinue) { 
      runner.run(notifier); 
     } 
    } 
} 
2

E 'possibile implementare un tale ciclo con TestRule s (dal JUnit 4.9)

Una semplice implementazione che passa ogni test 10 volte:

import org.junit.rules.TestRule; 
import org.junit.runner.Description; 
import org.junit.runners.model.Statement; 

public class SimpleRepeatRule implements TestRule { 

    private static class SimpleRepeatStatement extends Statement { 

     private final Statement statement; 

     private SimpleRepeatStatement(Statement statement) { 
      this.statement = statement; 
     } 

     @Override 
     public void evaluate() throws Throwable { 
      for (int i = 0; i < 10; i++) { 
       statement.evaluate(); 
      } 
     } 
    } 

    @Override 
    public Statement apply(Statement statement, Description description) { 
     return new SimpleRepeatStatement(statement); 
    } 
} 

utilizzo:

public class Run10TimesTest { 

    @Rule 
    public SimpleRepeatRule repeatRule = new SimpleRepeatRule(); 

    @Test 
    public void myTest(){...} 
} 

Per un implementazione più utile sulla base di un'annotazione che definisce quale metodo di prova deve essere eseguito quanto spesso dare un'occhiata a questo blog: http://www.codeaffine.com/2013/04/10/running-junit-tests-repeatedly-without-loops/

Problemi correlati