Making each test method run in its own instance of a test class with TestNG?

匿名 (未验证) 提交于 2019-12-03 03:06:01

问题:

So I thought the following code would run fine in TestNG, although it doesn't:

public class Tests {     int i = 0;      @Test     public void testA() {         Assert.assertEquals(0, i);         ++i;     }      @Test     public void testB() {         Assert.assertEquals(0, i);         ++i;     } } 

Is there a way to make TestNG fire up a new Tests class for each test method?

回答1:

The common solution is to use an @BeforeMethod method to setup test state,

@BeforeMethod public void setup() {    i = 0;  } 


回答2:

By far the most common solution to this issue I have found is to use ThreadLocal’s and just deal with the fact that you only have one instance of each Test Class. This deals with all the questions on how to deal with parallel/threaded tests. This works, but is a bit ugly.

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); } 

Now back to the root of your question, new instances for each method. I’ve been researching for a few weeks similar topics, and I have identified this is the number one issue I was personally having with TestNG. It has literally driven me crazy.

If I was to ignore the fact that your tests had a bunch of complexities, you could potentially hack together a work around to meet the requirements you listed.

A TestNG @Factory Factory allows you to create new instances of your test classes.

@Factory public Object[] factory(){     return new Object[]{new Tests(), new Tests()}; } 

I’ve now created two Tests instances, to be ran by testNG

Then the issue is your tests still fail, because it will try to run all test methods on your test classes. In order to hack around this you could implement a IMethodInterceptor, and hack together a solution to enforce that each Tests instance only run one method. Maintain a list of methods, and go through them one at a time.

Here is a brute example I hacked together.

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;     } } 

Then add your listener to the top of your Tests class

@Listeners(TestFactory.class) 

You can improve this by dynamically creating new instances of the tests in the factory. Also breaking the listener out into it's own file and numerous other improvements, but you get the gist.

Maybe a crazy solution like the above will work for you or someone else.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!