Один наблюдатель за тестированием результатов отдельных тестов в 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);
}
};
}
Вышеприведенный код работает, но проблема в том, что он приводит к тому, что мой Watcher сообщает результаты Suite, а не отдельные тесты. Кроме того, если тест завершился неудачно, пакет по-прежнему сообщает, что передан. Мой наблюдатель выглядит примерно так:
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;
}
}
Этот код хорошо комментируется как @Rule для отдельного теста (с отчетом для каждого теста индивидуально, не желательно), но, как указано выше, это не работает на уровне Suite, и я действительно не уверен, как чтобы он работал. Я думал, что смогу собрать список всех тестов, а в пакете закончить тесты и сбросить их, что позволит ExtentReport дать мне отчет обо всех тестах. Тем не менее, я не могу специально получить отдельные результаты тестов - я получу один тест обратно, с именем displayName() = Suite.
Как я могу отследить отдельные тесты, а затем очистить их, когда все закончится, и пусть ExtentWatcher позаботится о прохождении/сбое теста на основе теста, а не только один раз для пакета?
Ответы
Ответ 1
Я использую реализацию RunListener, которая регистрирует результаты в файле. Во-первых, у меня есть класс тестового бегуна, который вызывается для каждого набора тестов:
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 - это настраиваемый класс, который просто подсчитывает количество тестов, которые имеют: начальный, переданный, неудачный, игнорируемый.
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);
}
Ответ 2
Вышеприведенный код работает, но проблема в том, что это приводит к тому, что мой наблюдатель сообщая результаты Suite, а не отдельные тесты.
ClassRule
, указанные в классе TestSuite, выполняются на уровне класса, и они не могут быть выполнены для каждого отдельного теста. Следовательно, ваш наблюдатель не сообщает об отдельных тестах.
Поскольку вы заинтересованы в перечислении события для каждого отдельного тестового уровня, вы можете использовать org.junit.runner.notification.RunListener
(вместо Watcher). Чтобы избежать указания слушателя в каждом тестовом классе, вы можете реализовать свой собственный тестовый бегущий набор, который автоматически зарегистрирует пользовательский RunListener.
Например:
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);
}
}
И укажите этот бегун в классе Test Suite
@RunWith(SuiteRunner.class)
@Suite.SuiteClasses({ MyTest.class , MyTest2.class })
public class TestSuite {
@ClassRule
public static ExtentWatcher watcher = new ExtentWatcher();
}
Надеюсь, что это поможет.