Reputation: 121
I'm trying to use @Factory
to create multiple instances of a class and print the values in the same order that we have passed by using IMethodInterceptor
listener:
public class MainFactoryClass implements IMethodInterceptor {
@Factory
public Object[] mainFactory() {
Object[] data = new Object[6];
data[0] = new MainImpClass(9);
data[1] = new MainImpClass(10);
data[2] = new MainImpClass(11);
data[3] = new MainImpClass(12);
data[4] = new MainImpClass(13);
data[5] = new MainImpClass(14);
return data;
}
@Override
public List<IMethodInstance> intercept(List<IMethodInstance> list, ITestContext
iTestContext) {
Map<Integer, IMethodInstance> orders = new TreeMap<>();
for (IMethodInstance instance : list) {
MainImpClass testData = (MainImpClass) instance.getInstance();
orders.put(Integer.valueOf(testData.getA()), instance);
}
List<IMethodInstance> orderList = new ArrayList<IMethodInstance>(list.size());
for (Integer order : orders.keySet()) {
IMethodInstance test = orders.get(order);
orderList.add(test);
}
return orderList;
}
}
If I have 5 @Test
methods to print the values in the class, it only takes the last @Test method into account and prints the value. What am I doing wrong?. i.e. getValue1, getValue2, getValue3, getValue4
are not run.
Tried to use priority
or dependsOnMethods
. Code mentioned below:
@Listeners({ MainFactoryClass.class })
public class MainImpClass {
int a;
public MainImpClass(int a) {
this.a = a;
}
public int getA() {
return a;
}
@Test(priority = 0)
public void getValue1() {
System.out.println("Value from getValue1: " + a);
}
@Test(priority = 1)
public void getValue2() {
System.out.println("Value from getValue2: " + a);
}
@Test(priority = 2)
public void getValue3() {
System.out.println("Value from getValue3: " + a);
}
@Test(priority = 3)
public void getValue4() {
System.out.println("Value from getValue4: " + a);
}
@Test(priority = 4)
public void getValue5() {
System.out.println("Value from getValue5: " + a);
}
}
The output is in an order as we have created the instances but only from last @Test
.
Value from getValue5: 9
Value from getValue5: 10
Value from getValue5: 11
Value from getValue5: 12
Value from getValue5: 13
Value from getValue5: 14
testng.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Factory Suite">
<test thread-count="5" name=" Factory Test" group-by-
instances="true">
<classes>
<class name="com.trial.MainFactoryClass"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
Upvotes: 2
Views: 199
Reputation: 4935
Currently your configuration is such the there are 6 test instances and each contains 5 methods each. So a total of these 30 methods would be passed onto the intercept method. So since you are grouping them using getA
, only one method (last) among the 5 methods would be finally available in the map for an instance. One solution would be to implement @Max's solution by keeping a map of lists.
Another solution, assuming that you are using Java 8+, you could simplify the intercept method by using sorting instead of creating a map.
Comparator<IMethodInstance> customCompare =
Comparator.comparing(inst -> ((MainImpClass) inst.getInstance()).getA())
.thenComparing(inst -> inst.getMethod().getPriority());
// Now sort the list
list.sort(customCompare);
return list;
Sometimes, this might show some compile error, in which case you can use:
Comparator<Object> customCompare =
Comparator.comparing(inst -> ((MainImpClass) ((IMethodInstance) inst).getInstance()).getA())
.thenComparing(inst -> ((IMethodInstance) inst).getMethod().getPriority());
Note: Better to use separate classes for factory and interceptor as both are doing different things. Iterate the map using entrySet()
and use entry.getValue()
instead of iterating with keySet()
and accessing value by map.get(key)
. (Refer)
Upvotes: 1
Reputation: 2978
Your intercept
method works in the way, when you try to put multiple values with the same key to the map, so only the last value saved due to keys duplication.
So you see the last test per class..
The issue is here:
orders.put(Integer.valueOf(testData.getA()), instance);
The solution here might be
Map<Integer, List<IMethodInstance>> orders
append the List in the loop.
And by the end iterate over the keyset and make a single list from all the values.
Implement sorting with IMethodInterceptor
To change the order of the test you have to apply some sorting logic.
Here in your code, there is no sorting applied. You've created a new list, but the order was not changed.
I'll add an example, how to apply sorting by MainImpClass getA()
method result using custom Comparator. I'll add the implementation in MainFactoryClass
as you have currently, but usually I split factories and listeners to separate classes.
public class MainFactoryClass implements IMethodInterceptor {
@Factory
public Object[] mainFactory() {
Object[] data = new Object[6];
data[0] = new MainImpClass(9);
data[1] = new MainImpClass(10);
data[2] = new MainImpClass(11);
data[3] = new MainImpClass(12);
data[4] = new MainImpClass(13);
data[5] = new MainImpClass(14);
return data;
}
@Override
List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
// applying sorting is essential to change the tests order
methods.sort(new MainImpClassComparator());
return methods;
}
// internal class added, assumed it should compare only methods from MainImpClass
// here compareTo delegated to getA() results
class MainImpClassComparator implements Comparator<IMethodInstance> {
@Override
int compare(IMethodInstance o1, IMethodInstance o2) {
return ((MainImpClass)o1.getInstance()).getA().compareTo(((MainImpClass)o2.getInstance()).getA());
}
}
Upvotes: 1