org.testng.junit.JUnitTestRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of testng Show documentation
Show all versions of testng Show documentation
Testing framework for Java
package org.testng.junit;
import java.lang.reflect.Constructor;
import org.testng.ITestListener;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.TestNGException;
import org.testng.collections.Lists;
import org.testng.internal.ITestResultNotifier;
import org.testng.internal.InvokedMethod;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestListener;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.testng.*;
/**
* A JUnit TestRunner that records/triggers all information/events necessary to TestNG.
*
* @author Alexandru Popescu
*/
public class JUnitTestRunner implements TestListener, IJUnitTestRunner {
public static final String SUITE_METHODNAME = "suite";
private ITestResultNotifier m_parentRunner;
private Map m_tests= new WeakHashMap<>();
private List m_methods= Lists.newArrayList();
private Collection m_invokedMethodListeners = Lists.newArrayList();
public JUnitTestRunner() {
}
public JUnitTestRunner(ITestResultNotifier tr) {
m_parentRunner= tr;
}
/**
* Needed from TestRunner in order to figure out what JUnit test methods were run.
*
* @return the list of all JUnit test methods run
*/
@Override
public List getTestMethods() {
return m_methods;
}
@Override
public void setTestResultNotifier(ITestResultNotifier notifier) {
m_parentRunner= notifier;
}
/**
* @see junit.framework.TestListener#startTest(junit.framework.Test)
*/
@Override
public void startTest(Test test) {
m_tests.put(test, new TestRunInfo(Calendar.getInstance().getTimeInMillis()));
}
/**
* @see junit.framework.TestListener#addError(junit.framework.Test, java.lang.Throwable)
*/
@Override
public void addError(Test test, Throwable t) {
recordFailure(test, t);
}
/**
* @see junit.framework.TestListener#addFailure(junit.framework.Test, junit.framework.AssertionFailedError)
*/
@Override
public void addFailure(Test test, AssertionFailedError t) {
recordFailure(test, t);
}
private void recordFailure(Test test, Throwable t) {
TestRunInfo tri= m_tests.get(test);
if(null != tri) {
tri.setThrowable(t);
}
}
/**
* @see junit.framework.TestListener#endTest(junit.framework.Test)
*/
@Override
public void endTest(Test test) {
TestRunInfo tri= m_tests.get(test);
if(null == tri) {
return; // HINT: this should never happen. How do I protect myself?
}
org.testng.internal.TestResult tr= recordResults(test, tri);
runTestListeners(tr, m_parentRunner.getTestListeners());
}
public void setInvokedMethodListeners(Collection listeners) {
m_invokedMethodListeners = listeners;
}
private org.testng.internal.TestResult recordResults(Test test, TestRunInfo tri) {
JUnitTestClass tc= new JUnit3TestClass(test);
JUnitTestMethod tm= new JUnit3TestMethod(tc, test);
org.testng.internal.TestResult tr= new org.testng.internal.TestResult(tc,
test,
tm,
tri.m_failure,
tri.m_start,
Calendar.getInstance().getTimeInMillis(),
null);
if(tri.isFailure()) {
tr.setStatus(ITestResult.FAILURE);
m_parentRunner.addFailedTest(tm, tr);
}
else {
m_parentRunner.addPassedTest(tm, tr);
}
InvokedMethod im = new InvokedMethod(test, tm, new Object[0], tri.m_start, tr);
m_parentRunner.addInvokedMethod(im);
m_methods.add(tm);
for (IInvokedMethodListener l: m_invokedMethodListeners) {
l.beforeInvocation(im, tr);
}
return tr;
}
private static void runTestListeners(ITestResult tr, List listeners) {
for (ITestListener itl : listeners) {
switch(tr.getStatus()) {
case ITestResult.SKIP: {
itl.onTestSkipped(tr);
break;
}
case ITestResult.SUCCESS_PERCENTAGE_FAILURE: {
itl.onTestFailedButWithinSuccessPercentage(tr);
break;
}
case ITestResult.FAILURE: {
itl.onTestFailure(tr);
break;
}
case ITestResult.SUCCESS: {
itl.onTestSuccess(tr);
break;
}
case ITestResult.STARTED: {
itl.onTestStart(tr);
break;
}
default: {
assert false : "UNKNOWN STATUS:" + tr;
}
}
}
}
/**
* Returns the Test corresponding to the given suite. This is
* a template method, subclasses override runFailed(), clearStatus().
*/
protected Test getTest(Class testClass, String... methods) {
if (methods.length > 0) {
TestSuite ts = new TestSuite();
try {
Constructor c = testClass.getConstructor(String.class);
for (String m: methods) {
try {
ts.addTest((Test) c.newInstance(m));
} catch (InstantiationException ex) {
runFailed(testClass, "abstract class " + ex);
} catch (IllegalAccessException ex) {
runFailed(testClass, "constructor is not public " + ex);
} catch (IllegalArgumentException ex) {
runFailed(testClass, "actual and formal parameters differ " + ex);
} catch (InvocationTargetException ex) {
runFailed(testClass, "exception while instatiating test for method '" + m + "' " + ex);
}
}
} catch (NoSuchMethodException ex) {
runFailed(testClass, "no constructor accepting String argument found " + ex);
} catch (SecurityException ex) {
runFailed(testClass, "security exception " + ex);
}
return ts;
}
Method suiteMethod = null;
try {
suiteMethod = testClass.getMethod(SUITE_METHODNAME, new Class[0]);
}
catch (Exception e) {
// try to extract a test suite automatically
return new TestSuite(testClass);
}
if (!Modifier.isStatic(suiteMethod.getModifiers())) {
runFailed(testClass, "suite() method must be static");
return null;
}
Test test = null;
try {
test = (Test) suiteMethod.invoke(null, (Object[]) new Class[0]); // static method
if (test == null) {
return test;
}
}
catch (InvocationTargetException e) {
runFailed(testClass, "failed to invoke method suite():" + e.getTargetException().toString());
return null;
}
catch (IllegalAccessException e) {
runFailed(testClass, "failed to invoke method suite():" + e.toString());
return null;
}
return test;
}
/**
* A start
implementation that ignores the TestResult
* @param testClass the JUnit test class
*/
@Override
public void run(Class testClass, String... methods) {
start(testClass, methods);
}
/**
* Starts a test run. Analyzes the command line arguments and runs the given
* test suite.
*/
public TestResult start(Class testCase, String... methods) {
try {
Test suite = getTest(testCase, methods);
if(null != suite) {
return doRun(suite);
}
else {
runFailed(testCase, "could not create/run JUnit test suite");
}
}
catch (Exception e) {
runFailed(testCase, "could not create/run JUnit test suite: " + e.getMessage());
}
return null;
}
protected void runFailed(Class clazz, String message) {
throw new TestNGException("Failure in JUnit mode for class " + clazz.getName() + ": " + message);
}
/**
* Creates the TestResult to be used for the test run.
*/
protected TestResult createTestResult() {
return new TestResult();
}
protected TestResult doRun(Test suite) {
TestResult result = createTestResult();
result.addListener(this);
suite.run(result);
return result;
}
private static class TestRunInfo {
private final long m_start;
private Throwable m_failure;
public TestRunInfo(long start) {
m_start= start;
}
public boolean isFailure() {
return null != m_failure;
}
public void setThrowable(Throwable t) {
m_failure= t;
}
}
}