简体   繁体   English

一个测试观察器,用于报告JUnit Suite中各个测试的结果

[英]One test watcher to report results of individual tests in JUnit Suite

So I have a suite, something like this: 所以我有一个套件,如下所示:

@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);
        }
    };
}

The above code works, but the problem is that it results in my Watcher reporting the results of the Suite, not the individual tests. 上面的代码有效,但问题是它导致我的Watcher报告套件的结果,而不是单独的测试。 Also, if a test fails, the suite still reports as passed. 此外,如果测试失败,套件仍会报告为已通过。 My Watcher is something like this: 我的看守器是这样的:

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;
    }
}

This code works well annotated as @Rule for an individual test (with a report for each test individually, not desirable), but as per above, this isn't working on a Suite level and I'm really not sure how to make it work. 对于单个测试,此代码可以很好地注释为@Rule(每个测试都有一个单独的报告,不可取),但是如上所述,这不适用于套件级别,我真的不知道如何制作它工作。 I was thinking I could collect a list of all the tests, and in the suite, end the tests and flush them, which will allow ExtentReport to give me a report of all tests. 我以为我可以收集所有测试的列表,并在套件中结束测试并刷新它们,这将允许ExtentReport给我一份所有测试的报告。 However, I am unable to specifically get the individual test results - I will get one test back, with the displayName() = the Suite name. 但是,我无法专门获得单个测试结果 - 我将返回一个测试,其中displayName()=套件名称。

How can I track the individual tests, then flush them when all have finished, and let the ExtentWatcher take care of the pass/fail on a test by test basis, instead of just once for the suite? 如何跟踪各个测试,然后在完成所有测试后对其进行刷新,让ExtentWatcher在测试的基础上处理测试的通过/失败,而不仅仅是套件的一次?

I use a RunListener implementation, which logs the results in a file. 我使用RunListener实现,它将结果记录在一个文件中。 First, I have a test runner class that gets called for each test suite: 首先,我有一个为每个测试套件调用的测试运行器类:

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);
}

TestRun class is a custom class that simply counts the number of tests that have: started, passed, failed, ignored. TestRun类是一个自定义类,它只计算具有以下条件的测试数:启动,传递,失败,忽略。

TestRunListener implements org.junit.runner.notification.RunListener, and tracks information about test status, based on the callbacks (eg testFailure(), testFinished(), etc.). TestRunListener实现org.junit.runner.notification.RunListener,并根据回调(例如testFailure(),testFinished()等)跟踪有关测试状态的信息。

@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);
}

The above code works, but the problem is that it results in my Watcher reporting the results of the Suite, not the individual tests. 上面的代码有效,但问题是它导致我的Watcher报告套件的结果,而不是单独的测试。

ClassRule specified in the TestSuite class are executed at the class level and they cannot be executed for each individual tests. TestSuite类中指定的ClassRule在类级别执行,并且不能为每个单独的测试执行它们。 Hence your watcher is not reporting for individual tests. 因此,您的观察者不会报告个别测试。

Since you are interested in listing the event for each individual test level, you may use the org.junit.runner.notification.RunListener (instead of Watcher). 由于您有兴趣列出每个单独测试级别的事件,因此您可以使用org.junit.runner.notification.RunListener (而不是Watcher)。 In order to avoid to specify the listener in each test class, you can implement your own Suite test runner which will register the custom RunListener automatically. 为了避免在每个测试类中指定监听器,您可以实现自己的Suite测试运行器,它将自动注册自定义RunListener。

For example: 例如:

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);
    }
}

And specify this runner in your Test Suite class 并在Test Suite类中指定此运行器

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

Hope it helps. 希望能帮助到你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM