Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel test with shared mock

I'm writing a unit test class (using testng) that has mocked member variables (using Mockito) and running the tests in parallel. I initially set up the expected mock in an @BeforeClass method, and in each test case I break something by creating a Mockito.when for each exceptional case.

What I'm seeing (unsurprisingly) is that these tests aren't independent; the Mockito.when in one test case affects the others. I noticed that I could be set up the mocks before each test, and I changed the @BeforeClass to @BeforeMethod. I still didn't expect these to pass consistently, as the tests are all still operating on the same shared mock object at the same time. However, all the tests started passing consistently. My question is "why"? Will this eventually fail? No matter what I do (Thread.sleep, etc) I can't reproduce a failure.

Is using @BeforeMethod enough to make these tests independent? If so, can anyone explain why?

Example code below:

public class ExampleTest {
    @Mock
    private List<String> list;

    @BeforeClass // Changing to @BeforeMethod works for some reason
    public void setup() throws NoSuchComponentException, ADPRuntimeException {
        MockitoAnnotations.initMocks(this);
        Mockito.when(list.get(0)).thenReturn("normal");
    }

    @Test
    public void testNormalCase() throws InterruptedException {
        assertEquals(list.get(0), "normal"); // Fails with expected [normal] but found [exceptional]
    }

    @Test
    public void testExceptionalCase() throws InterruptedException {
        Mockito.when(list.get(0)).thenReturn("exceptional");
        assertEquals(list.get(0), "exceptional");
    }
}
like image 757
ChrisV Avatar asked Aug 25 '17 00:08

ChrisV


People also ask

Is parallel testing possible with TestNG?

TestNG helps to run test methods/classes/tests in parallel. Using the testng. xml file, one can specify parallel attributes to classes, tests, and methods. Java's multi-thread feature can also be applied by defining the number of threads for parallel testing in the thread attribute.

What is parallel testing with example?

Parallel Testing is a process to leverage automation testing capabilities by allowing the execution of the same tests simultaneously in multiple environments, real device combinations, and browser configurations. The overarching goal of parallel testing is to reduce time and resource constraints.

Do junit5 tests run in parallel?

enabled configuration parameter to true in junit-platform. properties file. Once parallel test execution property is enabled, the JUnit Jupiter engine will execute tests in parallel according to the provided configuration with declared synchronization mechanisms.

Does MSTest run tests in parallel?

The biggest advantage of MSTest is that it allows parallelization at the method level. As opposed to the other frameworks which only allow parallelization at the class level. So, for example, If you have 100 test methods in 5 classes, MSTest will let you run 100 tests in parallel.


1 Answers

The problem here is that TestNG creates one instance of your test class ExampleTest and this is the instance that is used by both of your @Test methods.

So when you used @BeforeClass, you would have random failures with testNormalCase() if testExceptionalCase() ran first and altered the state of your test class.

When you changed your annotation to be @BeforeMethod, it would cause the setup to be executed right before every @Test method was executed.

So the setup would fix the state for testNormalCase() which is why it would pass, and since testExceptionalCase() was internally altering the state using Mockito.when() and then running assertions, it would pass all the time as well.

But there's one scenario wherein your setup will still fail, viz., when you use parallel="methods" attribute in your <suite> tag within your TestNG suite xml file i.e., when you configure TestNG and instruct it to run every @Test method in parallel.

In that case, the Mockito.when() within testExceptionalCase() will affect the shared state [ since you are using this in a shared manner amongst all your @Test methods ] causing testNormalCase() to fail randomly.

To fix this, I would suggest that you do the following :

  • Don't share this between your @Test methods, but house it separately outside of your test class i.e., house all the data members of your test class in a separate pojo which would be mocked rather than mocking this.
  • Use a ThreadLocal to store the state which is being mocked by Mockito.when() and then run assertions on the ThreadLocal from within your @Test methods.
like image 110
Krishnan Mahadevan Avatar answered Sep 28 '22 02:09

Krishnan Mahadevan