0

I have the following JUnit tests, and can't work out why the second test does not pass, the value of i is 1 in both tests.

public class TestTest {

  private AtomicInteger ai = new AtomicInteger(1);

  @Test
  public void test1() {
    int i = ai.getAndIncrement();
    Assert.assertEquals(1, i);
  }

  @Test
  public void test2() {
    int i = ai.getAndIncrement();
    Assert.assertEquals(2, i);
  }
}

test1 passes and test2 fails with the following message:

java.lang.AssertionError: 
Expected :2
Actual   :1
Bentaye
  • 9,403
  • 5
  • 32
  • 45

3 Answers3

5

The tests are run on fresh instances. The behaviour of test1() can't affect test2() in any way, otherwise it could cause a single failing test to fail all other tests following it. That would make it harder to pinpoint the root of the problem, and you don't want that.

If you want to test behaviour between multiple calls, you'd need to either create a test that calls both those methods together as a single unit, or move on to integration testing where you can test larger amounts of code for correct working.

Your test is also logically wrong, since you're decrementing the value. Your (wrongly) expected value would be 0 instead of 2.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • sorry for the getAndIncrement , I meant getAndIncrement. Do you mean a fresh instance of the whole `TestTest` class? – Bentaye Mar 13 '18 at 08:23
  • As opposed to a fresh instance of...what...`AtomicInteger`? Yes of course a fresh instance of the test class. – Kayaman Mar 13 '18 at 08:24
  • Yes. Ok I understand, so the behaviour is that each test runs like if it was the only test in the class. – Bentaye Mar 13 '18 at 08:26
  • Exactly. That way it's testing only what it's supposed to, and is immune to any side effects that could otherwise be caused by other tests. – Kayaman Mar 13 '18 at 08:42
2
  • Each @Test annotated method runs indepedent with new reinititalized ai value (1) therefore test2 fails.
  • You better run test1and test2 in one single test to detect the right working getAndIncrement() results (belongs to your actual issue). Have a look at the code listing Ai-increment.

    //*Code listing: Ai-increment*    
    private AtomicInteger ai;
    
    @Before
    public void before() {
        ai = new AtomicInteger(1);
    }
    
    @Test
    public void test() {
        assertEquals(1, ai.getAndIncrement());
        assertEquals(2, ai.getAndIncrement());
    }
    
  • Furthermore you can use @Before instead of private AtomicInteger ai = new AtomicInteger(1);. So you insure for each test the assigned value 1 in the atomic way.

1

You can add 'static' to your AtomicInteger initialization and each test instance will use the same variable. Like this:

private static AtomicInteger ai = new AtomicInteger(1);

But you have another problem - you cannot guarantee that test1 will be running first and test2 second. So additionally you need to re-write tests with this in mind or use something like @TestMethodOrder(Alphanumeric.class)

  • That works indeed. And also agreed that it is bad practice to have your tests dependent on each other. – Bentaye Jun 18 '21 at 12:14