2016-01-25 25 views
15

Così ho una suite, qualcosa di simile:Un test watcher di riportare i risultati dei singoli test in JUnit Suite

@RunWith(Suite.class) 
@Suite.SuiteClasses({TestClass1.class, TestClass2.class, TestClass3.class}) 
public class TestSuite { 

    static List<ExtentTest> extentTestList = new ArrayList<>(); 

    @ClassRule 
    public static ExtentWatcher extentWatcher = new ExtentWatcher() { 
     @Override 
     protected void starting(Description description) { 
      extentTestList.addAll(extentWatcher.getTests()); 
     } 
     @Override 
     protected void finished(Description description) { 
      extentWatcher.flushReports(extentTestList); 
     } 
    }; 
} 

Il codice precedente funziona, ma il problema è che il risultato e 'il mio Osservatore riportare i risultati della Suite, non i singoli test. Inoltre, se un test fallisce, la suite continua a essere trasmessa. Il mio Watcher è qualcosa di simile:

public class ExtentWatcher extends TestWatcher { 

    // A little set up to give the report a date in the file name 
    private DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); 
    private Date date = new Date(); 
    private String fileDate = dateFormat.format(date); 
    private String reportName = "./Test_Report_" + fileDate + ".html"; 
    public ExtentReports extent; 
    ArrayList<ExtentTest> testList = new ArrayList<>(); 

    public ExtentWatcher() { 
     extent = createReport(); 
    } 

     // If test passed, watcher will record this with Extent Reports 
     @Override 
     protected void succeeded(Description description) { 
      ExtentTest test = extent.startTest(description.getDisplayName()); 
      test.log(LogStatus.PASS, "Test Run Successful"); 
      testList.add(test); 
     } 

     // Likewise in case of failure 
     @Override 
     protected void failed(Throwable e, Description description) { 
      ExtentTest test = extent.startTest(description.getDisplayName()); 
      test.log(LogStatus.FAIL, "Test Failure: " + e.toString()); 
      testList.add(test); 
     } 

    /** 
    * These methods do the legwork - this file is based off of an example I found @ www.kieftsoft.nl/?p=81 
    * Eventually we can add some screenshot logic here, but just a clean test report and version info will do 
    */ 

    private ExtentReports createReport() { 
     // Create the report - Extent just needs a little config 
     ExtentReports extent = new ExtentReports(reportName, false); 
     extent.config().reportName("Test Report: " + fileDate); 
     return extent; 
    } 

    public void flushReports(List<ExtentTest> testList) { 
     // This ends the test and then sends (flushes) everything to the html document 
     for(ExtentTest test : testList) extent.endTest(test); 
     extent.flush(); 
    } 

    public List<ExtentTest> getTests() { 
     return testList; 
    } 
} 

Questo codice funziona bene annotato come @Rule per un singolo test (con un rapporto per ogni test singolarmente, non auspicabile), ma di cui al precedente, questo non sta lavorando su un livello Suite e non sono davvero sicuro di come farlo funzionare. Stavo pensando di raccogliere un elenco di tutti i test e, nella suite, terminare i test e scaricarli, il che consentirà a ExtentReport di fornirmi una relazione su tutti i test. Tuttavia, non sono in grado di ottenere in modo specifico i risultati dei singoli test: riceverò un test indietro, con displayName() = il nome della suite.

Come è possibile tenere traccia dei singoli test, quindi svuotarli quando tutti sono terminati e lasciare che ExtentWatcher si occupi del pass/fail su un test per test, anziché solo una volta per la suite?

+0

Funziona dopo aver aggiunto flushReports in riuscito e non riuscito? – Karthik

+0

Non correlato al problema: perché non si aggiorna all'ultima versione? – Karthik

+0

No, se eseguo il flush in riuscito o non riuscito riceverò un report per ogni test. Attualmente sto usando l'ultima versione. –

risposta

1

Uso un'implementazione RunListener, che registra i risultati in un file. In primo luogo, ho una classe test runner che viene chiamato per ogni suite di test:

public Result run(String suite) { 
    Class<?> suiteClass = null; 
    try { 
     suiteClass = Class.forName(suite); 
    } catch (ClassNotFoundException ex) { 
     return null; 
    } 
    JUnitCore core = new JUnitCore(); 
    this.testRun = new TestRun(testLogging, suite); 
    core.addListener(new TestRunListener(testLogging, testRun)); 
    Result result = core.run(suiteClass); 
    return(result); 
} 

classe TestRun è una classe personalizzata che conta semplicemente il numero di test che hanno: ha iniziato, superato, non superato, ignorato.

TestRunListener implementa org.junit.runner.notification.RunListener e tiene traccia delle informazioni sullo stato del test, in base ai callback (ad esempio testFailure(), testFinished() e così via).

@Override 
public void testFailure(Failure failure) throws Exception { 
    classLogger.log(Level.CONFIG, failure.getMessage()); 
    classLogger.log(Level.CONFIG, failure.getTestHeader()); 
    classLogger.log(Level.CONFIG, failure.getTrace()); 
    classLogger.log(Level.CONFIG, failure.getDescription().getDisplayName()); 
    if (failure.getException() != null) { 
    classLogger.log(Level.CONFIG, failure.getException().getMessage()); 
    } 
    super.testFailure(failure); 

    Description description = failure.getDescription(); 
    Test test = processTestResult(TestStatus.FAIL, description); 
    if (test == null) { 
    classLogger.log(Level.SEVERE, "TEST IS NULL:" + description.getDisplayName()); 
    return; 
    } 

    classLogger.log(Level.CONFIG, failure.getMessage()+ " " + description.getDisplayName()); 

    test.setFailureMessage(description.getDisplayName()); 
    test.setFailureException(failure.getException()); 
    LogRecord record = new LogRecord(Level.CONFIG, failure.getMessage()); 
    record.setParameters(new Object[] { test, failure }); 
    testFailuresLogger.log(record); 
} 
0

Il codice precedente funziona, ma il problema è che il risultato e 'il mio Osservatore riportare i risultati della Suite, non i singoli test.

ClassRule specificato nella classe TestSuite sono eseguiti a livello di classe e non possono essere eseguiti per ogni singolo test. Quindi il tuo osservatore non sta segnalando per i singoli test.

Poiché è interessato a elencare l'evento per ogni singolo livello di test, è possibile utilizzare org.junit.runner.notification.RunListener (anziché Watcher). Per evitare di specificare il listener in ogni classe di test, è possibile implementare il proprio runner di test della Suite che registrerà automaticamente RunListener personalizzato.

Ad esempio:

public class SuiteRunner extends Suite { 
    public SuiteRunner(Class<?> klass) throws InitializationError { 
     super(klass, new JUnit4Builder()); 
    } 

    @Override 
    public void run(RunNotifier notifier) { 
     notifier.addFirstListener(new RunListener() { 
      @Override 
      public void testRunStarted(Description description) throws Exception { 
       // add to watcher 
      } 

      @Override 
      public void testFailure(Failure failure) throws Exception { 
       // add to watcher 
      } 

     }); 
     super.run(notifier); 
    } 
} 

E specificare questo corridore nella tua class Test Suite

@RunWith(SuiteRunner.class) 
@Suite.SuiteClasses({ MyTest.class , MyTest2.class }) 
public class TestSuite { 
    @ClassRule 
    public static ExtentWatcher watcher = new ExtentWatcher(); 
} 

Speranza che aiuta.