在 TestNG 中使用 IMethodInterceptor 作为 Listener 时,只有最后一个 @Test 被执行
Only the last @Test is being executed when using IMethodInterceptor as Listener in TestNG
我正在尝试使用 @Factory
创建 class 的多个实例,并按照我们使用 IMethodInterceptor
侦听器传递的相同顺序打印值:
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;
}
}
如果我有 5 个 @Test
方法来打印 class 中的值,它只考虑最后一个 @Test 方法并打印值。我究竟做错了什么?。即 getValue1, getValue2, getValue3, getValue4
不是 运行.
尝试使用 priority
或 dependsOnMethods
。代码如下:
@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);
}
}
输出按照我们创建实例的顺序排列,但仅从最后一个 @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 -->
您的 intercept
方法以这种方式工作,当您尝试将具有相同键的多个值放入地图时,由于键重复,只有最后一个值被保存。
所以你看到最后一个测试 class..
问题在这里:
orders.put(Integer.valueOf(testData.getA()), instance);
这里的解决方案可能是
Map<Integer, List<IMethodInstance>> orders
在循环中追加列表。
最后遍历键集并从所有值中生成一个列表。
用IMethodInterceptor
实现排序
要更改测试顺序,您必须应用一些排序逻辑。
在您的代码中,没有应用排序。您创建了一个新列表,但顺序没有改变。
我将添加一个示例,如何使用自定义比较器按 MainImpClass getA()
方法结果应用排序。我将像您目前所做的那样在 MainFactoryClass
中添加实现,但通常我会将工厂和侦听器拆分为单独的 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());
}
}
当前您的配置是这样的,有 6 个测试实例,每个实例包含 5 个方法。所以总共这 30 个方法将传递给拦截方法。因此,由于您使用 getA
对它们进行分组,因此 5 种方法中只有一种方法(最后一种)最终在实例的地图中可用。一种解决方案是通过保留列表映射来实施@Max 的解决方案。
另一个解决方案,假设您使用的是Java 8+,您可以通过使用排序而不是创建映射来简化拦截方法。
Comparator<IMethodInstance> customCompare =
Comparator.comparing(inst -> ((MainImpClass) inst.getInstance()).getA())
.thenComparing(inst -> inst.getMethod().getPriority());
// Now sort the list
list.sort(customCompare);
return list;
有时,这可能会显示一些编译错误,在这种情况下,您可以使用:
Comparator<Object> customCompare =
Comparator.comparing(inst -> ((MainImpClass) ((IMethodInstance) inst).getInstance()).getA())
.thenComparing(inst -> ((IMethodInstance) inst).getMethod().getPriority());
注意:最好为工厂和拦截器使用单独的 类,因为两者在做不同的事情。使用 entrySet()
迭代映射并使用 entry.getValue()
而不是使用 keySet()
迭代并通过 map.get(key)
访问值。 (Refer)
我正在尝试使用 @Factory
创建 class 的多个实例,并按照我们使用 IMethodInterceptor
侦听器传递的相同顺序打印值:
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;
}
}
如果我有 5 个 @Test
方法来打印 class 中的值,它只考虑最后一个 @Test 方法并打印值。我究竟做错了什么?。即 getValue1, getValue2, getValue3, getValue4
不是 运行.
尝试使用 priority
或 dependsOnMethods
。代码如下:
@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);
}
}
输出按照我们创建实例的顺序排列,但仅从最后一个 @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 -->
您的 intercept
方法以这种方式工作,当您尝试将具有相同键的多个值放入地图时,由于键重复,只有最后一个值被保存。
所以你看到最后一个测试 class..
问题在这里:
orders.put(Integer.valueOf(testData.getA()), instance);
这里的解决方案可能是
Map<Integer, List<IMethodInstance>> orders
在循环中追加列表。
最后遍历键集并从所有值中生成一个列表。
用IMethodInterceptor
要更改测试顺序,您必须应用一些排序逻辑。
在您的代码中,没有应用排序。您创建了一个新列表,但顺序没有改变。
我将添加一个示例,如何使用自定义比较器按 MainImpClass getA()
方法结果应用排序。我将像您目前所做的那样在 MainFactoryClass
中添加实现,但通常我会将工厂和侦听器拆分为单独的 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());
}
}
当前您的配置是这样的,有 6 个测试实例,每个实例包含 5 个方法。所以总共这 30 个方法将传递给拦截方法。因此,由于您使用 getA
对它们进行分组,因此 5 种方法中只有一种方法(最后一种)最终在实例的地图中可用。一种解决方案是通过保留列表映射来实施@Max 的解决方案。
另一个解决方案,假设您使用的是Java 8+,您可以通过使用排序而不是创建映射来简化拦截方法。
Comparator<IMethodInstance> customCompare =
Comparator.comparing(inst -> ((MainImpClass) inst.getInstance()).getA())
.thenComparing(inst -> inst.getMethod().getPriority());
// Now sort the list
list.sort(customCompare);
return list;
有时,这可能会显示一些编译错误,在这种情况下,您可以使用:
Comparator<Object> customCompare =
Comparator.comparing(inst -> ((MainImpClass) ((IMethodInstance) inst).getInstance()).getA())
.thenComparing(inst -> ((IMethodInstance) inst).getMethod().getPriority());
注意:最好为工厂和拦截器使用单独的 类,因为两者在做不同的事情。使用 entrySet()
迭代映射并使用 entry.getValue()
而不是使用 keySet()
迭代并通过 map.get(key)
访问值。 (Refer)