org.testng.internal.TestMethodWorker 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.internal;
import org.testng.ClassMethodMap;
import org.testng.IMethodInstance;
import org.testng.ITestClass;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.collections.Lists;
import org.testng.internal.thread.ThreadUtil;
import org.testng.internal.thread.graph.IWorker;
import org.testng.xml.XmlSuite;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* FIXME: reduce contention when this class is used through parallel invocation due to
* invocationCount and threadPoolSize by not invoking the @BeforeClass and @AfterClass
* which are already invoked on the original method.
*
* This class implements Runnable and will invoke the ITestMethod passed in its
* constructor on its run() method.
*
* @author Cedric Beust
* @author Alexandru Popescu
*/
public class TestMethodWorker implements IWorker {
// Map of the test methods and their associated instances
// It has to be a set because the same method can be passed several times
// and associated to a different instance
private IMethodInstance[] m_methodInstances;
private final IInvoker m_invoker;
private final Map m_parameters;
private final XmlSuite m_suite;
private List m_testResults = Lists.newArrayList();
private final ConfigurationGroupMethods m_groupMethods;
private final ClassMethodMap m_classMethodMap;
private final ITestContext m_testContext;
public TestMethodWorker(IInvoker invoker,
IMethodInstance[] testMethods,
XmlSuite suite,
Map parameters,
ConfigurationGroupMethods groupMethods,
ClassMethodMap classMethodMap,
ITestContext testContext)
{
m_invoker = invoker;
m_methodInstances = testMethods;
m_suite = suite;
m_parameters = parameters;
m_groupMethods = groupMethods;
m_classMethodMap = classMethodMap;
m_testContext = testContext;
}
/**
* Retrieves the maximum specified timeout of all ITestNGMethods to
* be run.
*
* @return the max timeout or 0 if no timeout was specified
*/
@Override
public long getTimeOut() {
long result = 0;
for (IMethodInstance mi : m_methodInstances) {
ITestNGMethod tm = mi.getMethod();
if (tm.getTimeOut() > result) {
result = tm.getTimeOut();
}
}
return result;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder("[Worker thread:" + Thread.currentThread().getId()
+ " priority:" + getPriority() + " ");
for (IMethodInstance m : m_methodInstances) {
result.append(m.getMethod()).append(" ");
}
result.append("]");
return result.toString();
}
/**
* Run all the ITestNGMethods passed in through the constructor.
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
for (IMethodInstance testMthdInst : m_methodInstances) {
ITestNGMethod testMethod = testMthdInst.getMethod();
ITestClass testClass = testMethod.getTestClass();
invokeBeforeClassMethods(testClass, testMthdInst);
// Invoke test method
try {
invokeTestMethods(testMethod, testMthdInst.getInstance(), m_testContext);
}
finally {
invokeAfterClassMethods(testClass, testMthdInst);
}
}
}
protected void invokeTestMethods(ITestNGMethod tm, Object instance,
ITestContext testContext)
{
// Potential bug here: we look up the method index of tm among all
// the test methods (not very efficient) but if this method appears
// several times and these methods are run in parallel, the results
// are unpredictable... Need to think about this more (and make it
// more efficient)
List testResults =
m_invoker.invokeTestMethods(tm,
m_suite,
m_parameters,
m_groupMethods,
instance,
testContext);
if (testResults != null) {
m_testResults.addAll(testResults);
}
}
/**
* Invoke the @BeforeClass methods if not done already
* @param testClass
* @param mi
*/
protected void invokeBeforeClassMethods(ITestClass testClass, IMethodInstance mi) {
// if no BeforeClass than return immediately
// used for parallel case when BeforeClass were already invoked
if( (null == m_classMethodMap) || (null == m_classMethodMap.getInvokedBeforeClassMethods())) {
return;
}
ITestNGMethod[] classMethods= testClass.getBeforeClassMethods();
if(null == classMethods || classMethods.length == 0) {
return;
}
// the whole invocation must be synchronized as other threads must
// get a full initialized test object (not the same for @After)
Map> invokedBeforeClassMethods =
m_classMethodMap.getInvokedBeforeClassMethods();
// System.out.println("SYNCHRONIZING ON " + testClass
// + " thread:" + Thread.currentThread().getId()
// + " invokedMap:" + invokedBeforeClassMethods.hashCode() + " "
// + invokedBeforeClassMethods);
synchronized(testClass) {
Set