0

Suppose I have one test class with three test methods. The tests may either run serially or in two separate threads. Each test method requires its own instance of a collaborator (such as a resource of some kind). However, this would not seem to cut it:

public class MyTestClass {
    private Resource resource;

    @BeforeMethod public void setupResource() {}
    @AfterMethod public void tearDownResource() {}

    @Test public void testMethod1() {}
    @Test public void testMethod2() {}
    @Test public void testMethod3() {}
}

This seems to work when run serially, but if we run the three test methods in parallel (with method granularity), it would seem that because all three tests are invoked via the same instance, the resource variable ends up being overwritten repeatedly.

So, how about this:

public class MyTestClass {
    private static ThreadLocal<Resource> resource;

    @BeforeMethod public void setupResource() {}
    @AfterMethod public void tearDownResource() {}

    @Test public void testMethod1() {}
    @Test public void testMethod2() {}
    @Test public void testMethod3() {}
}

This seems plausible, and it looks like it can old up if I throw in @DataProvider and test listeners as well (provided setupResource() and tearDownResource() is properly implemented, so that if there are two threads to run tests on, the third method doesn't have any "leftovers" from the first).

Having said that, it seems quite cumbersome to have a @BeforeMethod, an @AfterMethod, and wrapping the collaborator (Resource) in a ThreadLocal. Is there any other good "test-local" alternatives worthy of consideration?

Kelvin Chung
  • 1,327
  • 1
  • 11
  • 23

1 Answers1

0

I think you can set up a threadlocal container separately. Something like below; create a Mythreadlocal container class.

public class ThreadLocalContextObject{
  private Resource resource;
  // getter and setter for above
}

public class MyThreadLocal {
  public static final ThreadLocal threadLocal = new ThreadLocal();

  public static void set(ThreadLocalContextObject ctx) {
    threadLocal.set(ctx);
  }

  public static void unset() {
    threadLocal.remove();
  }
  public static ThreadLocalContextObject get() {
    return threadLocal.get();
  }
}

Then from @BeforeMethod you can set the context object holding the resource in the MyThreadLocal. And from the @AfterMethod you can unset it from the threadlocal storage by calling unset.

Note unsetting the threadlocal is necessary failing which can easily cause you run out of memory.

The threadlocal will gurantee the local storage of the resource for the thread executing a particular test case.

So answering your question the threadlocal might be the easiest and safest way to do this stuff according to me.

Sumeet Sharma
  • 2,573
  • 1
  • 12
  • 24