Parallel="methods" with private class variables

629 views
Skip to first unread message

haison3000

unread,
May 11, 2007, 3:09:22 PM5/11/07
to testng-users
Hi,

It seems that when TestNG runs in parrallel="methods", all methods in
a class share the same class variables. In other word, testNG does
instantiate the test object only once and invokes methods of that
object concurrently.

For me, it seems bad since multiple methods could modify the class
variables and stumbles on other thread.

Can anybody clarify that my understanding is correct"
--haison

Cédric Beust ♔

unread,
May 11, 2007, 5:50:38 PM5/11/07
to testng...@googlegroups.com
Your understanding is correct.  How about using a ThreadLocal to save per-thread data?

--
Cedric
--
Cédric

haison3000

unread,
May 11, 2007, 6:51:16 PM5/11/07
to testng-users
That is my plan to work around the issue.
Thanks for the verification.

On May 11, 2:50 pm, "Cédric Beust ♔ " <cbe...@google.com> wrote:
> Your understanding is correct. How about using a ThreadLocal to save
> per-thread data?
>
> --
> Cedric
>

Alexandru Popescu ☀

unread,
May 12, 2007, 7:46:29 AM5/12/07
to testng...@googlegroups.com
On 5/12/07, haison3000 <haiso...@yahoo.com> wrote:
>
> That is my plan to work around the issue.

This is not an issue. TestNG advocated right from the beginning that
state testing is important. Moreover, TestNG is not just an unit
testing framework (where argueable the instance per test method fits)
and so TestNG has gone this different path.

./alex
--
.w( the_mindstorm )p.
TestNG co-founder
EclipseTestNG Creator

Gili T.

unread,
Mar 6, 2014, 2:37:45 PM3/6/14
to testng...@googlegroups.com
Alex,

What is the point of sharing class fields when using parallel="methods"? I mean, what could you possibly share across methods which could be meaningful if you are running each method in its own thread?

Doesn't parallel="methods" implicitly require each method to execute independent from others?

I guess my point is, for parallel="methods", I think it would be a lot easier to write unit tests if a separate class instance was loaded per @Test.

Let me know if I missed anything.

Thanks,
Gili

Michael May

unread,
Mar 7, 2014, 1:14:04 AM3/7/14
to testng...@googlegroups.com
I'll try tomorrow to see if ThreadLocal will work with generating TestId's. Not sure if it will work since I think @BeforeMethod, @AfterMethod and @Test run on different threads. Having TestId's would be extremely useful because you could output them on custom ReportNG reports and get test log information by just searching by the TestId. The BeforeMethod/AfterMethod will need to be used to access the ITestResult to set the attribute for the TestId.

Michael May

unread,
Mar 7, 2014, 3:31:39 PM3/7/14
to testng...@googlegroups.com
This is how I got unique test id's for tests when running parallel = 'methods'. Hopefully this will be useful for someone.

create the TestIdListener:

public class TestIdListener implements ITestListener {
   
    private static AtomicInteger testIdIndex;
   
    static {
        testIdIndex = new AtomicInteger(0);
    }
   
    public TestIdListener() {
    }
   
    @Override
    public void onFinish(ITestContext context) {
    }

    @Override
    public void onStart(ITestContext context) {
    }

    @Override
    public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
    }
   
    @Override
    public void onTestFailure(ITestResult result) {
    }

    @Override
    public void onTestSkipped(ITestResult result) {
    }
   
    @Override
    public void onTestSuccess(ITestResult result) {
    }
   
    @Override
    public void onTestStart(ITestResult result) {
        synchronized(testIdIndex) {
            int testId = testIdIndex.incrementAndGet();
            result.setAttribute("test_id", "TID-" + testId);
        }
    }
}

@Listeners({
    TestIdListener.class
    })
public abstract class TestIdTestCase {
    public String getTestId() {
        return (String) Reporter.getCurrentTestResult().getAttribute("test_id");
    }
}

I tried using ThreadLocal but the @BeforeMethod and @AfterMethod runs on a different thread than the @Test methods. Maybe the inititialization could go out of the Listener and into the @BeforeMethod, but I think getTestId would have to stay the same to work consistently with parallel tests.

Michael May

unread,
Mar 7, 2014, 3:46:00 PM3/7/14
to testng...@googlegroups.com
So I think if you want to use variables at the test level, instead of the class level - which they are shared with all the test cases; you would need to save the variable using an attribute in ITestResult.

Michael May

unread,
Mar 7, 2014, 4:09:07 PM3/7/14
to testng...@googlegroups.com
Yeah, you don't need to create a listener, It's cleaner to do the setup in the @BeforeMethod method.

public abstract class TestIdTestCase {

    private static AtomicInteger testIdIndex;
   
    static {
        testIdIndex = new AtomicInteger(0);
    }

    @BeforeMethod
    public void beforeMethodTestIdTestCase(ITestResult result) {

        synchronized(testIdIndex) {
            int testId = testIdIndex.incrementAndGet();
            result.setAttribute("test_id", "TID-" + testId);
        }
    }

cowwoc

unread,
Mar 7, 2014, 4:39:31 PM3/7/14
to testng...@googlegroups.com
Hi Michael,

I wasn't aware of Reporter.getCurrentTestResult() so thanks for pointing this out. It is kind of weird/confusing that @Test allows injection of ITestContext but not ITestResult. I mean, I actually prefer the API approach instead of injection but http://testng.org/doc/documentation-main.html#dependency-injection does a poor job of documenting this possibility. I find the documentation in general to be full of holes. I mean, there is a lot of information there but it also leaves a lot of open questions.

... When I originally posted this question I wanted to share data between @BeforeMethod, @Test, @AfterMethod using parallel="method" on a per-method basis. ThreadLocal turned out to be a great fit, but I'm glad that your shared your technique as well because it is quite useful for sharing test-wide data.

I wish (someone) would add this useful information into the documentation somehow ;)

Thanks again,
Gili

--
You received this message because you are subscribed to a topic in the Google Groups "testng-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/testng-users/oWxn6YocEAQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to testng-users...@googlegroups.com.
To post to this group, send email to testng...@googlegroups.com.
Visit this group at http://groups.google.com/group/testng-users.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages