Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Junit reinitialize the class with each test method invocation?

When i run the below code, both test cases come true:

import static junit.framework.Assert.assertEquals;

import org.junit.Test;

public class MyTest{
    private int count;

    @Before
    public void before(){
        count=1;
    }

    @Test
    public void test1(){
        count++;
        assertEquals(2, count); 
    }

    @Test
    public void test2(){
        count++;
        assertEquals(2, count); 
    }
}

EXPECTED BEHAVIOUR

  1. test1 - success
  2. test2 - fail(as expected that count will become 3)

ACTUAL BEHAVIOUR

  1. test1 - success
  2. test2 - success

Why junit is reinitializing class/variable with each test method invocation. It is a bug in junit or is provided intentionally.

like image 875
Prateek Avatar asked Oct 15 '13 12:10

Prateek


People also ask

Does JUnit creates a new instance for each test?

JUnit creates a new instance of the test class before invoking each @Test method. This helps provide independence between test methods and avoids unintentional side effects in the test code. Because each test method runs on a new test class instance, we can't reuse instance variable values across test methods.

Does @after run after every test?

Create Test fixture before each test.  @Before - method that is run before every test case. setUp( ) is the traditional name.  @After - method that is run after every test case.

What happens if a JUnit test method is declared as?

If a JUnit test method is declared as "private", it compiles successfully. But the execution will fail. This is because JUnit requires that all test methods must be declared as "public".

Which is used to invoke a method after execution of each test method?

(i) onStart(): This method is invoked after the test class is instantiated and before any configuration method is called.


5 Answers

It is because of test isolation.

No test should depend on another.

like image 116
René Link Avatar answered Sep 22 '22 15:09

René Link


New Instance of MyTest for each test method

For each test method a new instance of MyTest will be created this is the behavior of Junit.

So in your case for both methods the variable count will have value 1, and thus the value of count++ will be 2 for both the test methods and hence the test cases pass.

public class MyTest{
   public MyTest(){
      // called n times
      System.out.println("Constructor called for MyTest");
   }

   @Before //called n times
   public void setUp(){
      System.out.println("Before called for MyTest");
   }
    
   //n test methods
}

If you execute the code above with 2 test methods:

Output will be:

Constructor called for MyTest
Before called for MyTest
//test execution
Constructor called for MyTest
Before called for MyTest

Edit:

Isolation from the F.I.R.S.T principle of testing

Test frameworks help you in doing the right thing, a very important property of unit tests is isolation.

By creating a new instance every test method, the dirty SUT is thrown away. So that we have a fresh state for every test.

Read about F.I.R.S.T principle of testing.

like image 28
Narendra Pathai Avatar answered Sep 24 '22 15:09

Narendra Pathai


Look at the documentation of org.junit.runner.Runner:

The default runner implementation guarantees that the instances of the test case class will be constructed immediately before running the test and that the runner will retain no reference to the test case instances, generally making them available for garbage collection.

Unit tests should be independant otherwise it becomes unmaintable. Note that the order of executed methods is not guaranteed (unless you use the annotation @FixMethodOrder).

like image 31
LaurentG Avatar answered Sep 25 '22 15:09

LaurentG


Answer for JUnit 5

In JUnit5, this behavior is controlled using the @TestInstance annotation. The annotation can take as value one of two lifecycle qualifiers:

  • @TestInstance(Lifecycle.PER_CLASS): The test class will be initialized once for all the methods in the class.
  • @TestInstance(Lifecycle.PER_METHOD): The test class will be reinitialized before each test method (the behavior described in other answers).

If a test class is not annotated with @TestInstance, the default behavior is PER_METHOD.

For more details, see Test Instance Lifecycle in the JUnit5 User Guide.

like image 37
SDJ Avatar answered Sep 21 '22 15:09

SDJ


If you want to use test class's member variable for all tests , without it being reinitialised to null, then make it static.

like image 43
Deepthi Avatar answered Sep 23 '22 15:09

Deepthi