org.testng.internal.TestResult 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
A testing framework for the JVM
package org.testng.internal;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;
import org.testng.IAttributes;
import org.testng.IClass;
import org.testng.ITest;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.TestNGException;
import org.testng.TestRunner;
import org.testng.collections.Lists;
import org.testng.collections.Objects;
import javax.annotation.Nonnull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
/** This class represents the result of a test. */
public class TestResult implements ITestResult {
private ITestNGMethod m_method = null;
private List skippedDueTo = Lists.newArrayList();
private boolean skipAnalysed = false;
private int m_status = CREATED;
private Throwable m_throwable = null;
private long m_startMillis = 0;
private long m_endMillis = 0;
private String m_name = null;
private String m_host;
private Object[] m_parameters = {};
private String m_instanceName;
private ITestContext m_context;
private int parameterIndex;
private boolean m_wasRetried;
private final IAttributes m_attributes = new Attributes();
private TestResult() {
//defeat instantiation. We have factory methods.
}
public static TestResult newEmptyTestResult() {
return new TestResult();
}
public static TestResult newTestResultFor(ITestNGMethod method) {
return newContextAwareTestResult(method, null);
}
public static TestResult newContextAwareTestResult(ITestNGMethod method, ITestContext ctx) {
TestResult result = newEmptyTestResult();
long time = System.currentTimeMillis();
result.init(method, ctx, null, time, 0L);
return result;
}
public static TestResult newTestResultWithCauseAs(ITestNGMethod method, ITestContext ctx,
Throwable t) {
TestResult result = newEmptyTestResult();
long time = System.currentTimeMillis();
result.init(method, ctx, t, time, time);
return result;
}
public static TestResult newEndTimeAwareTestResult(ITestNGMethod method, ITestContext ctx,
Throwable t, long start) {
TestResult result = newEmptyTestResult();
long time = System.currentTimeMillis();
result.init(method, ctx, t, start, time);
return result;
}
public static TestResult newTestResultFrom(TestResult result, ITestNGMethod method,
ITestContext ctx, long start) {
TestResult testResult = newEmptyTestResult();
testResult.setHost(result.getHost());
testResult.setParameters(result.getParameters());
testResult.init(method, ctx, null, start, 0L);
TestResult.copyAttributes(result, testResult);
return testResult;
}
private void init(ITestNGMethod method, ITestContext ctx, Throwable t, long start, long end) {
m_throwable = t;
m_instanceName = method.getTestClass().getName();
if (null == m_throwable) {
m_status = ITestResult.SUCCESS;
}
m_startMillis = start;
m_endMillis = end;
m_method = method;
m_context = ctx;
Object instance = method.getInstance();
// Calculate the name: either the method name, ITest#getTestName or
// toString() if it's been overridden.
if (instance == null) {
m_name = m_method.getMethodName();
return;
}
if (instance instanceof ITest) {
m_name = ((ITest) instance).getTestName();
if (m_name != null) {
return;
}
m_name = m_method.getMethodName();
if (TestRunner.getVerbose() > 1) {
String msg = String.format(
"Warning: [%s] implementation on class [%s] returned null. Defaulting to method name",
ITest.class.getName(), instance.getClass().getName());
System.err.println(msg);
}
return;
}
if (method.getTestClass().getTestName() != null) {
m_name = method.getTestClass().getTestName();
return;
}
String string = instance.toString();
// Only display toString() if it's been overridden by the user
m_name = getMethod().getMethodName();
try {
if (!Object.class
.getMethod("toString")
.equals(instance.getClass().getMethod("toString"))) {
m_instanceName =
string.startsWith("class ") ? string.substring("class ".length()) : string;
m_name = m_name + " on " + m_instanceName;
}
} catch (NoSuchMethodException ignore) {
// ignore
}
}
@Override
public void setEndMillis(long millis) {
m_endMillis = millis;
}
/**
* If this result's related instance implements ITest or use @Test(testName=...), returns its test
* name, otherwise returns null.
*/
@Override
public String getTestName() {
if (this.m_method == null) {
return null;
}
Object instance = this.m_method.getInstance();
if (instance instanceof ITest) {
return ((ITest) instance).getTestName();
}
if (m_method.getTestClass().getTestName() != null) {
return m_method.getTestClass().getTestName();
}
return null;
}
@Override
public String getName() {
return m_name;
}
/** @return Returns the method. */
@Override
public ITestNGMethod getMethod() {
return m_method;
}
/** @param method The method to set. */
public void setMethod(ITestNGMethod method) {
m_method = method;
}
/** @return Returns the status. */
@Override
public int getStatus() {
return m_status;
}
/** @param status The status to set. */
@Override
public void setStatus(int status) {
m_status = status;
}
@Override
public boolean isSuccess() {
return ITestResult.SUCCESS == m_status;
}
/** @return Returns the testClass. */
@Override
public IClass getTestClass() {
return m_method.getTestClass();
}
/** @return Returns the throwable. */
@Override
public Throwable getThrowable() {
return m_throwable;
}
/** @param throwable The throwable to set. */
@Override
public void setThrowable(Throwable throwable) {
m_throwable = throwable;
}
/** @return Returns the endMillis. */
@Override
public long getEndMillis() {
return m_endMillis;
}
/** @return Returns the startMillis. */
@Override
public long getStartMillis() {
return m_startMillis;
}
@Override
public String toString() {
List output = Reporter.getOutput(this);
return Objects.toStringHelper(getClass())
.omitNulls()
.omitEmptyStrings()
.add("name", getName())
.add("status", toString(m_status))
.add("method", m_method)
.add("output", output != null && output.size() > 0 ? output.get(0) : null)
.toString();
}
private static String toString(int status) {
switch (status) {
case SUCCESS:
return "SUCCESS";
case FAILURE:
return "FAILURE";
case SKIP:
return "SKIP";
case SUCCESS_PERCENTAGE_FAILURE:
return "SUCCESS WITHIN PERCENTAGE";
case STARTED:
return "STARTED";
case CREATED:
return "CREATED";
default:
throw new TestNGException("Encountered an un-defined test status of [" + status + "].");
}
}
@Override
public String getHost() {
return m_host;
}
public void setHost(String host) {
m_host = host;
}
@Override
public Object[] getParameters() {
return m_parameters;
}
@Override
public void setParameters(Object[] parameters) {
m_parameters = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
// Copy parameter if possible because user may change it later
if (parameters[i] instanceof Cloneable) {
try {
Method clone = parameters[i].getClass().getDeclaredMethod("clone");
m_parameters[i] = clone.invoke(parameters[i]);
} catch (NoSuchMethodException
| InvocationTargetException
| IllegalAccessException
| SecurityException e) {
m_parameters[i] = parameters[i];
}
} else {
m_parameters[i] = parameters[i];
}
}
}
@Override
public Object getInstance() {
return IParameterInfo.embeddedInstance(this.m_method.getInstance());
}
@Override
public Object[] getFactoryParameters() {
IParameterInfo instance = this.m_method.getFactoryMethodParamsInfo();
if (instance != null) {
return instance.getParameters();
}
return new Object[0];
}
@Override
public Object getAttribute(String name) {
return m_attributes.getAttribute(name);
}
@Override
public void setAttribute(String name, Object value) {
m_attributes.setAttribute(name, value);
}
@Override
public Set getAttributeNames() {
return m_attributes.getAttributeNames();
}
@Override
public Object removeAttribute(String name) {
return m_attributes.removeAttribute(name);
}
@Override
public ITestContext getTestContext() {
return m_context;
}
public void setContext(ITestContext context) {
m_context = context;
}
@Override
public int compareTo(@Nonnull ITestResult comparison) {
return Long.compare(getStartMillis(), comparison.getStartMillis());
}
@Override
public String getInstanceName() {
return m_instanceName;
}
@Override
public void setTestName(String name) {
m_name = name;
}
void setParameterIndex(int parameterIndex) {
this.parameterIndex = parameterIndex;
}
public int getParameterIndex() {
return parameterIndex;
}
public boolean wasRetried() {
return m_wasRetried;
}
public void setWasRetried(boolean wasRetried) {
this.m_wasRetried = wasRetried;
}
public List getSkipCausedBy() {
if (this.m_status != SKIP || skipAnalysed) {
return Collections.unmodifiableList(skippedDueTo);
}
skipAnalysed = true;
//check if there were any config failures
Set skippedConfigs = m_context.getFailedConfigurations().getAllResults();
for (ITestResult skippedConfig : skippedConfigs) {
if (isGlobalFailure(skippedConfig) || isRelated(skippedConfig)) {
//If there's a failure in @BeforeTest/@BeforeSuite/@BeforeClass
//then the reason is most often just one method.
skippedDueTo.add(skippedConfig.getMethod());
}
if (belongToSameGroup(skippedConfig)) {
//If its @BeforeGroups then there's a chance that there could be more than one
//method. So lets add everything.
skippedDueTo.add(skippedConfig.getMethod());
}
}
if (!skippedDueTo.isEmpty()) {
//If we found atleast one skipped due to reason, then its time to return back.
return Collections.unmodifiableList(skippedDueTo);
}
//Looks like we didnt have any configuration failures. So some upstream method perhaps failed.
if (m_method.getMethodsDependedUpon().length==0) {
//Maybe group dependencies exist ?
if (m_method.getGroupsDependedUpon().length==0) {
return Collections.emptyList();
}
List upstreamGroups = Arrays.asList(m_method.getGroupsDependedUpon());
List allFailures = Lists.merge(m_context.getFailedTests().getAllResults(),
m_context.getFailedButWithinSuccessPercentageTests().getAllResults());
skippedDueTo = allFailures.stream()
.map(ITestResult::getMethod)
.filter(method -> {
List currentMethodGroups = Arrays.asList(method.getGroups());
List interection = Lists.intersection(upstreamGroups, currentMethodGroups);
return !interection.isEmpty();
}).collect(Collectors.toList());
return Collections.unmodifiableList(skippedDueTo);
}
List upstreamMethods = Arrays.asList(m_method.getMethodsDependedUpon());
//So we have dependsOnMethod failures
List allfailures = Lists.merge(m_context.getFailedTests().getAllResults(),
m_context.getFailedButWithinSuccessPercentageTests().getAllResults());
skippedDueTo = allfailures.stream()
.map(ITestResult::getMethod)
.filter(method -> upstreamMethods.contains(method.getQualifiedName()))
.collect(Collectors.toList());
return Collections.unmodifiableList(skippedDueTo);
}
private static boolean isGlobalFailure(ITestResult result) {
ITestNGMethod m = result.getMethod();
return m.isBeforeTestConfiguration() || m.isBeforeSuiteConfiguration();
}
private boolean isRelated(ITestResult result) {
ITestNGMethod m = result.getMethod();
if (!m.isBeforeClassConfiguration() && !m.isBeforeMethodConfiguration()) {
return false;
}
Object current = this.getInstance();
Object thatObject = result.getInstance();
return current.getClass().isAssignableFrom(thatObject.getClass()) ||
thatObject.getClass().isAssignableFrom(current.getClass());
}
private boolean belongToSameGroup(ITestResult result) {
ITestNGMethod m = result.getMethod();
if (!m.isBeforeGroupsConfiguration()) {
return false;
}
String[] mygroups = this.m_method.getGroups();
if (mygroups.length == 0 || m.getGroups().length ==0) {
return false;
}
List cfgMethodGroups = Arrays.asList(m.getGroups());
return Arrays.stream(mygroups).anyMatch(cfgMethodGroups::contains);
}
static void copyAttributes(ITestResult source, ITestResult target) {
source
.getAttributeNames()
.forEach(name -> target.setAttribute(name, source.getAttribute(name)));
}
}