3

Like the title says I keep getting fields that are null down in the test cases even though I've initiated them in the @Before method as a one-time set-up. The only exception is that the first test that runs, works.

I was able to replicate the behaviour with the following code:

public class NetworkTest extends TestCase{
    private static Boolean oneTimeSetUpDone = false;
    private Client client;

    @Before
    public void setUp(){
        if(!oneTimeSetUpDone){
            client = new Client();

            oneTimeSetUpDone = true;
        }   
    }

    @Test
    public void testConnection(){
        System.out.println(client);
        assertFalse(true);
    }

    @Test
    public void testMultiConnection(){
        System.out.println(client);
        assertFalse(true);
    }

Am I missing something here or why would the fields get cleared after the first test is run?

Anders R. Bystrup
  • 15,729
  • 10
  • 59
  • 55
David S
  • 195
  • 5
  • 19
  • 2
    note : you can use `@BeforeClass` to setup all test contains in class and called only once – flafoux May 12 '15 at 09:50
  • @NitinDandriyal Right I know that but why would my fields initiated inside the if-statement be null for consecutive tests? – David S May 12 '15 at 09:54
  • If its just one time why not initialize `Client` during declaration itself – Nitin Dandriyal May 12 '15 at 09:55
  • assertFalse(true) = means it will fail – flafoux May 12 '15 at 09:58
  • 1
    http://stackoverflow.com/questions/14010222/junit-new-instance-before-invoking-each-test-method-what-are-the-benefits Just use static instance if you want reuse since JUnit creates a new instance of the test class before invoking each @Test – Nitin Dandriyal May 12 '15 at 09:59
  • note: You're mixing JUnit 3 and JUnit 4 test style. Please remove `extends TestCase` in order to get a correct JUnit 4 test. – Stefan Birkner May 12 '15 at 11:12

2 Answers2

5

@Before is run before each test - you should think of every @Test running in a new instance of the test class, and @Before sets up that instance (pro tip: look at the class' .hashCode() - it's different in each test method).

You can use @BeforeClass in your case.

Cheers,

Anders R. Bystrup
  • 15,729
  • 10
  • 59
  • 55
  • Hmm, okay but surely this should work also? It has on previous test I've written and [this](http://stackoverflow.com/a/12088135/1959534) post where I took it from had it working. – David S May 12 '15 at 09:59
  • Yes, but then your `client` attribute needs to be `static` as well then (since it has to be shared among all class instances)! In fact you could then disperse with the flag and test on null-ness of `client` - and perhaps `synchronized` access if you're a bit paranoid. – Anders R. Bystrup May 12 '15 at 10:02
  • I accepted the answer but now I'm curious why my previous set up that has this exact same layout worked, it instantiated a class inside the if statement and then used it throughout the tests. – David S May 12 '15 at 10:10
1

Each test case in your test class, gets it's own copy of the instance variables. However your static field

private static Boolean oneTimeSetUpDone = false;

is shared among all the test cases. For each test case, the @Before method is execuded. What happens is that you're initializing the instance fields only for the first case - it's the if statement that sets the above flag to true, thus leaving the instance variables for other test cases uninitialized.

You have two options, depending on the instance fields. First answer this question, does it make sense to reuse the same instance field objects for each test case?

If it does, you could make them static, and your @Before method shall do fine as it is now. Otherwise, you should remove the boolean flag, along with the if statement. That is, you need to initialize the instance variables for each test case, since they need to be "fresh" for each test case.

P.S. make your boolean field simply boolean instead of Boolean.

Evdzhan Mustafa
  • 3,645
  • 1
  • 24
  • 40