Java 使用TestNG使每个测试方法在自己的测试类实例中运行?
因此,我认为以下代码在TestNG中可以很好地运行,但事实并非如此:Java 使用TestNG使每个测试方法在自己的测试类实例中运行?,java,unit-testing,testing,testng,Java,Unit Testing,Testing,Testng,因此,我认为以下代码在TestNG中可以很好地运行,但事实并非如此: public class Tests { int i = 0; @Test public void testA() { Assert.assertEquals(0, i); ++i; } @Test public void testB() { Assert.assertEquals(0, i); ++i;
public class Tests {
int i = 0;
@Test
public void testA() {
Assert.assertEquals(0, i);
++i;
}
@Test
public void testB() {
Assert.assertEquals(0, i);
++i;
}
}
有没有办法让TestNG为每个测试方法启动一个新的测试类?常见的解决方案是使用@BeforeMethod方法来设置测试状态
@BeforeMethod
public void setup() {
i = 0;
}
到目前为止,我发现这个问题最常见的解决方案是使用ThreadLocal,只需处理每个测试类只有一个实例的事实。这涉及如何处理并行/线程测试的所有问题。这是可行的,但有点难看
private ThreadLocal<Integer> i = new ThreadLocal<>();
@BeforeMethod
public void setup() {
i.set(0);
}
@Test
public void testA() {
Integer i1 = i.get();
Assert.assertEquals(0, i.get().intValue());
i.set(i1 + 1);
}
@Test
public void testB() {
Integer i1 = i.get();
Assert.assertEquals(0, i.get().intValue());
i.set(i1 + 1);
}
我现在创建了两个测试
实例,由testNG运行
然后问题是您的测试仍然失败,因为它将尝试在您的测试类上运行所有测试方法。为了解决这个问题,您可以实现一个IMethodInterceptor,并将一个解决方案整合在一起,以强制每个测试实例只运行一个方法。维护一个方法列表,并一次浏览一个
这是一个我拼凑的野蛮例子
public class TestFactory implements IMethodInterceptor {
private List<String> methodsToRun = new ArrayList<>();
private List<Object> testInstances = new ArrayList<>();
@Factory
public Object[] factory(){
return new Object[]{new Tests(), new Tests()};
}
@Override
public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
ArrayList<IMethodInstance> tempList = new ArrayList<>();
for(IMethodInstance i: methods){
if(testInstances.contains(i.getInstance())){
continue;
}
String mName = i.getMethod().getConstructorOrMethod().getName();
if(!methodsToRun.contains(mName)){
tempList.add(i);
methodsToRun.add(mName);
testInstances.add(i.getInstance());
}
}
return tempList;
}
}
您可以通过在工厂中动态创建测试的新实例来改进这一点。还将侦听器分解到它自己的文件和许多其他改进中,但您得到了要点
也许像上面这样疯狂的解决方案会对你或其他人有效 你想这样做有什么特别的原因吗?是的,因为我想运行几个与彼此无关的不同测试!我不想保留他们之间的状态!此外,如果它保持状态,我怎么知道哪些测试是第一个运行的,哪些是第二个或第三个?如果我想测试我的堆栈实现,那将需要20个单元测试,您是否希望有人创建20个测试类?“如果您想运行彼此无关的测试,为什么不将它们放在不同的类中?“问题恰恰在于它们之间有很多联系,这就是为什么我希望它们在同一个测试类中,这也是为什么在测试之间清理它们很重要的原因!啊,难道没有更好的方法吗?@Cedric,我对框架有实现两个目的的方法完全没有问题:困扰我的是,它缺乏一种真正的实现单元测试的方法,即在测试之间重置状态。拥有@BeforeMethod充其量只能算是一种黑客行为。例如,一个建议是在TestNG中添加一个@statelementBetweentTests说明(虽然IMO状态重用不应该是默认行为,但这只是我的观点)。换句话说,在单元测试框架中,我倾向于默认行为是在测试之间丢弃状态(即自动)的解决方案虽然我确实理解,对于系统/集成测试,可能会首选相反的方法。剩下的问题是TestNG的主要目标是什么:)@CedricBeust“BeforeMethod”解决方案可能适用于顺序测试,但如何适用于并行测试。让我们假设在上面的例子中有两种并行运行的测试方法。实例变量“i”将具有不可预测的值…不是吗?不知道你是否想到了解决这个问题的办法。我同意阿比吉特的观点@CedricBeust如果需要并行测试的状态,我们应该怎么做?
public class TestFactory implements IMethodInterceptor {
private List<String> methodsToRun = new ArrayList<>();
private List<Object> testInstances = new ArrayList<>();
@Factory
public Object[] factory(){
return new Object[]{new Tests(), new Tests()};
}
@Override
public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
ArrayList<IMethodInstance> tempList = new ArrayList<>();
for(IMethodInstance i: methods){
if(testInstances.contains(i.getInstance())){
continue;
}
String mName = i.getMethod().getConstructorOrMethod().getName();
if(!methodsToRun.contains(mName)){
tempList.add(i);
methodsToRun.add(mName);
testInstances.add(i.getInstance());
}
}
return tempList;
}
}
@Listeners(TestFactory.class)