Skip to content

Commit

Permalink
Support params in Factory in ITestResult
Browse files Browse the repository at this point in the history
Closes #1041
  • Loading branch information
krmahadevan committed Aug 30, 2018
1 parent b543b4f commit 43f3104
Show file tree
Hide file tree
Showing 18 changed files with 280 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Current
Fixed: GITHUB-1041: Factory data-provider parameters not displayed in test-result (Krishnan Mahadevan)
Fixed: GITHUB-1893: Streamline invocation of "init" method within TestResult to be private (Krishnan Mahadevan)
Fixed: GITHUB-1892: Configurable InvokedMethodListener (Krishnan Mahadevan)
Fixed: GITHUB-435: Apply <packages> at suite level to all tests (Siegmar Alber)
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/testng/ITestNGMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,8 @@ public interface ITestNGMethod extends Cloneable {
default boolean isDataDriven() {
return false;
}

default Object getRawInstance() {
return null;
}
}
6 changes: 6 additions & 0 deletions src/main/java/org/testng/ITestResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ public interface ITestResult extends IAttributes, Comparable<ITestResult> {
/** The instance on which this method was run. */
Object getInstance();

/**
* @return - A parameter array that was passed to a factory method (or) an empty object array
* otherwise.
*/
Object[] getFactoryParameters();

/**
* If this result's related instance implements ITest or use @Test(testName=...), returns its test
* name, otherwise returns null.
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/testng/TestClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ private void initTestClassesAndInstances() {
//
Object[] instances = getInstances(true);
for (Object instance : instances) {
instance = IParameterInfo.embeddedInstance(instance);
if (instance instanceof ITest) {
testName = ((ITest) instance).getTestName();
break;
Expand Down Expand Up @@ -107,7 +108,8 @@ private void initMethods() {
ITestNGMethod[] methods = testMethodFinder.getTestMethods(m_testClass, xmlTest);
m_testMethods = createTestMethods(methods);

for (Object instance : iClass.getInstances(false)) {
for (Object eachInstance : iClass.getInstances(false)) {
Object instance = IParameterInfo.embeddedInstance(eachInstance);
m_beforeSuiteMethods =
ConfigurationMethod.createSuiteConfigurationMethods(
testMethodFinder.getBeforeSuiteMethods(m_testClass),
Expand Down
19 changes: 16 additions & 3 deletions src/main/java/org/testng/internal/BaseTestMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public String getMethodName() {

@Override
public Object getInstance() {
return m_instance;
return IParameterInfo.embeddedInstance(m_instance);
}

/** {@inheritDoc} */
Expand Down Expand Up @@ -319,7 +319,7 @@ public boolean equals(Object obj) {
? other.m_testClass == null
: other.m_testClass != null
&& m_testClass.getRealClass().equals(other.m_testClass.getRealClass())
&& m_instance == other.getInstance();
&& getInstance() == other.getInstance();

return isEqual && getConstructorOrMethod().equals(other.getConstructorOrMethod());
}
Expand Down Expand Up @@ -456,7 +456,8 @@ private String computeSignature() {
.append("[pri:")
.append(getPriority())
.append(", instance:")
.append(m_instance)
.append(getInstance())
.append(instanceParameters())
.append("]");

return result.toString();
Expand All @@ -466,6 +467,14 @@ public String getSimpleName() {
return m_method.getDeclaringClass().getSimpleName() + "." + m_method.getName();
}

private String instanceParameters() {
Object instance = getRawInstance();
if (instance instanceof IParameterInfo) {
return ", instance params:" + Arrays.toString(((IParameterInfo) instance).getParameters());
}
return "";
}

protected String getSignature() {
if (m_signature == null) {
m_signature = computeSignature();
Expand Down Expand Up @@ -715,4 +724,8 @@ public Map<String, String> findMethodParameters(XmlTest test) {
public String getQualifiedName() {
return getRealClass().getName() + "." + getMethodName();
}

public Object getRawInstance() {
return m_instance;
}
}
6 changes: 5 additions & 1 deletion src/main/java/org/testng/internal/ClassImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public Object[] getInstances(boolean create) {
int m_instanceCount = m_instances.size();
m_instanceHashCodes = new long[m_instanceCount];
for (int i = 0; i < m_instanceCount; i++) {
m_instanceHashCodes[i] = m_instances.get(i).hashCode();
m_instanceHashCodes[i] = computeHashCode(m_instances.get(i));
}
return result;
}
Expand All @@ -211,4 +211,8 @@ public String toString() {
public void addInstance(Object instance) {
m_instances.add(instance);
}

private static int computeHashCode(Object instance) {
return IParameterInfo.embeddedInstance(instance).hashCode();
}
}
15 changes: 9 additions & 6 deletions src/main/java/org/testng/internal/FactoryMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Map;
import java.util.Set;

import java.util.stream.Collectors;
import org.testng.IDataProviderListener;
import org.testng.IInstanceInfo;
import org.testng.IObjectFactory;
Expand Down Expand Up @@ -127,8 +128,8 @@ private static String[] getAllGroups(
return groups.toArray(new String[0]);
}

public Object[] invoke() {
List<Object> result = Lists.newArrayList();
public IParameterInfo[] invoke() {
List<IParameterInfo> result = Lists.newArrayList();

Map<String, String> allParameterNames = Maps.newHashMap();
Parameters.MethodParameters methodParameters =
Expand Down Expand Up @@ -166,12 +167,14 @@ public Object[] invoke() {
if (com.getMethod() != null) {
Object[] testInstances = (Object[]) com.getMethod().invoke(m_instance, parameters);
if (indices == null || indices.isEmpty()) {
result.addAll(Arrays.asList(testInstances));
result.addAll(Arrays.stream(testInstances).map(instance ->
new ParameterInfo(instance, parameters)
).collect(Collectors.toList()));
} else {
for (Integer index : indices) {
int i = index - position;
if (i >= 0 && i < testInstances.length) {
result.add(testInstances[i]);
result.add(new ParameterInfo(testInstances[i], parameters));
}
}
}
Expand All @@ -188,7 +191,7 @@ public Object[] invoke() {
throw new IllegalStateException(
"Unsupported ITestObjectFactory " + objectFactory.getClass());
}
result.add(instance);
result.add(new ParameterInfo(instance, parameters));
}
position++;
}
Expand All @@ -204,7 +207,7 @@ public Object[] invoke() {
t);
}

return result.toArray(new Object[0]);
return result.toArray(new IParameterInfo[0]);
}

@Override
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/org/testng/internal/IParameterInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.testng.internal;

/**
* Represents the ability to retrieve the parameters associated with a factory method.
*/
public interface IParameterInfo {

/**
* @return - The actual instance associated with a factory method
*/
Object getInstance();

/**
* @return - The parameters associated with the factory method as an array.
*/
Object[] getParameters();

static Object embeddedInstance(Object original) {
if (original instanceof IParameterInfo) {
return ((IParameterInfo) original).getInstance();
}
return original;
}

}
21 changes: 21 additions & 0 deletions src/main/java/org/testng/internal/ParameterInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.testng.internal;

public class ParameterInfo implements IParameterInfo {
private Object instance;
private Object[] parameters;

public ParameterInfo(Object instance, Object[] parameters) {
this.instance = instance;
this.parameters = parameters;
}

@Override
public Object getInstance() {
return instance;
}

@Override
public Object[] getParameters() {
return parameters;
}
}
11 changes: 6 additions & 5 deletions src/main/java/org/testng/internal/TestNGClassFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class TestNGClassFinder extends BaseClassFinder {

private static final String PREFIX = "[TestNGClassFinder]";
private final ITestContext m_testContext;
private final Map<Class<?>, List<Object>> m_instanceMap = Maps.newHashMap();
private final Map<Class<?>, List<Object>> m_instanceMap = Maps.newHashMap();
private final Map<Class<? extends IDataProviderListener>, IDataProviderListener>
m_dataProviderListeners;
private final ITestObjectFactory objectFactory;
Expand Down Expand Up @@ -183,13 +183,14 @@ private ClassInfoMap processFactory(IClass ic, ConstructorOrMethod factoryMethod
"The factory " + fm + " returned a null instance" + "at index " + i);
}
Class<?> oneMoreClass;
if (IInstanceInfo.class.isAssignableFrom(o.getClass())) {
IInstanceInfo<?> ii = (IInstanceInfo) o;
Object objToInspect = IParameterInfo.embeddedInstance(o);
if (IInstanceInfo.class.isAssignableFrom(objToInspect.getClass())) {
IInstanceInfo<?> ii = (IInstanceInfo) objToInspect;
addInstance(ii);
oneMoreClass = ii.getInstanceClass();
} else {
addInstance(o);
oneMoreClass = o.getClass();
oneMoreClass = objToInspect.getClass();
}
if (!classExists(oneMoreClass)) {
moreClasses.addClass(oneMoreClass);
Expand Down Expand Up @@ -315,7 +316,7 @@ private <T> void addInstance(IInstanceInfo<T> ii) {
}

private void addInstance(Object o) {
addInstance(o.getClass(), o);
addInstance(IParameterInfo.embeddedInstance(o).getClass(), o);
}

// Class<S> should be replaced by Class<? extends T> but java doesn't fail as expected
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/org/testng/internal/TestResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,16 @@ public void setParameters(Object[] parameters) {

@Override
public Object getInstance() {
return this.m_method.getInstance();
return IParameterInfo.embeddedInstance(this.m_method.getInstance());
}

@Override
public Object[] getFactoryParameters() {
Object instance = this.m_method.getRawInstance();
if (instance instanceof IParameterInfo) {
return ((IParameterInfo) instance).getParameters();
}
return new Object[0];
}

@Override
Expand Down
41 changes: 25 additions & 16 deletions src/main/java/org/testng/reporters/EmailableReporter2.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,22 +436,10 @@ private void writeScenario(int scenarioIndex, String label, ITestResult result)
// Write test parameters (if any)
Object[] parameters = result.getParameters();
int parameterCount = (parameters == null ? 0 : parameters.length);
if (parameterCount > 0) {
writer.print("<tr class=\"param\">");
for (int i = 1; i <= parameterCount; i++) {
writer.print("<th>Parameter #");
writer.print(i);
writer.print("</th>");
}
writer.print("</tr><tr class=\"param stripe\">");
for (Object parameter : parameters) {
writer.print("<td>");
writer.print(Utils.escapeHtml(Utils.toString(parameter)));
writer.print("</td>");
}
writer.print("</tr>");
hasRows = true;
}
hasRows = dumpParametersInfo("Factory Parameter", result.getFactoryParameters());
parameters = result.getParameters();
parameterCount = (parameters == null ? 0 : parameters.length);
hasRows = dumpParametersInfo("Parameter", result.getParameters());

// Write reporter messages (if any)
List<String> reporterMessages = Reporter.getOutput(result);
Expand Down Expand Up @@ -506,6 +494,27 @@ private void writeScenario(int scenarioIndex, String label, ITestResult result)
writer.println("<p class=\"totop\"><a href=\"#summary\">back to summary</a></p>");
}

private boolean dumpParametersInfo(String prefix, Object[] parameters) {
int parameterCount = (parameters == null ? 0 : parameters.length);
if (parameterCount == 0) {
return false;
}
writer.print("<tr class=\"param\">");
for (int i = 1; i <= parameterCount; i++) {
writer.print(String.format("<th>%s #", prefix));
writer.print(i);
writer.print("</th>");
}
writer.print("</tr><tr class=\"param stripe\">");
for (Object parameter : parameters) {
writer.print("<td>");
writer.print(Utils.escapeHtml(Utils.toString(parameter)));
writer.print("</td>");
}
writer.print("</tr>");
return true;
}

protected void writeReporterMessages(List<String> reporterMessages) {
writer.print("<div class=\"messages\">");
Iterator<String> iterator = reporterMessages.iterator();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package test.factory.issue1041;

import java.util.List;
import java.util.Objects;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
import org.testng.collections.Lists;

public class FactoryAnnotatedConstructorExample {
static List<FactoryAnnotatedConstructorExample> objects = Lists.newArrayList();

private int data;

@Factory(dataProvider = "dp")
public FactoryAnnotatedConstructorExample(int data) {
this.data = data;
addInstance(this);
}

private static void addInstance(FactoryAnnotatedConstructorExample instance) {
objects.add(instance);
}

@DataProvider(name = "dp")
public static Object[][] getData() {
return new Object[][]{
{1},
{2}
};
}

@Test
public void testMethod() {
Assert.assertTrue(data > 0);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FactoryAnnotatedConstructorExample that = (FactoryAnnotatedConstructorExample) o;
return data == that.data;
}

@Override
public int hashCode() {
return Objects.hash(data);
}
}
Loading

0 comments on commit 43f3104

Please sign in to comment.