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
Testing framework for Java
package org.testng.internal;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
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.collections.Lists;
import org.testng.collections.Objects;
/** 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 final String id = UUID.randomUUID().toString();
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.setParameterIndex(result.getParameterIndex());
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;
if (RuntimeBehavior.isMemoryFriendlyMode()) {
m_method = new LiteWeightTestNGMethod(method);
} else {
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 (Utils.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.isEmpty() ? 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;
}
public 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 -> matches(upstreamMethods, method))
.collect(Collectors.toList());
return Collections.unmodifiableList(skippedDueTo);
}
private static boolean matches(List upstreamMethods, ITestNGMethod method) {
if (upstreamMethods.contains(method.getQualifiedName())
|| upstreamMethods.contains(method.getMethodName())) {
return true;
}
return upstreamMethods.stream()
.map(Pattern::compile)
.anyMatch(
each ->
each.matcher(method.getQualifiedName()).matches()
|| each.matcher(method.getMethodName()).matches());
}
public String id() {
return id;
}
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);
}
public static void copyAttributes(ITestResult source, ITestResult target) {
source
.getAttributeNames()
.forEach(name -> target.setAttribute(name, source.getAttribute(name)));
}
}