Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing Initialization Code only once for multiple test classes

I am writing unit test cases for my code. I am using PowerMockito with Junit. I have written an initialization code which will take care of all the initialization stuff in my application. Below is the way my code is structured:

Class ServiceInitializer{
    public static isInitialized = Boolean.FALSE;

    public static void initialize(){
        //Initilization Code Goes Here
        isInitialized = Boolean.TRUE;
    }
}

@RunWith(PowerMockRunner.class)
class BaseTest{

    @Before
    public void preTest(){
        //some code
    }


    static{
        if(!ServiceInitializer.isInitialized){
            ServiceInitializer.initialize();
        }
    }

    @After
    public void postTest(){
        //some code
    }
}

public TestClass1 extends BaseTest{
    @Test
    public void testMethodA_1(){//test code}

    @Test
    public void testMethodA_2(){//test code}

    @Test
    public void testMethodA_3(){//test code}
}

public TestClass2 extends BaseTest{
    @Test
    public void testMethodB_1(){//test code}

    @Test
    public void testMethodB_2(){//test code}

    @Test
    public void testMethodB_3(){//test code}
}

I am executing these test cases as ant script using Junit and batchtest targets as given below:

<junit printsummary="yes" haltonfailure="yes" showoutput="yes">
            <classpath refid="JUnitTesting.classpath"/>
            <batchtest haltonerror="false" haltonfailure="no" todir="${junit.output.dir}/raw">
                <formatter type="plain"/>
                <formatter type="xml"/>     
                <fileset dir="${basedir}/src">
                  <include name="**/Test*.java"/>
                </fileset>
            </batchtest>
        </junit>

I am able to execute the test cases just fine but its the initialization code, which is written in the static block of BaseTest class, which is causing problem for me. Whenever New Test Class starts its execution, "ServiceInitializer.initialize();" is getting called every time. So, say if I have 10 Test Classes then this method is getting called 10 times. I want to get control over it such that it only gets executed only once no matter how many Test Classes I have. How Can I achieve that? Is that even possible with JUnit?

--Update--

I know there is @BeforeClass annotation available which executes the block of code exactly once for each test class. But this is not fulfilling my requirements since as soon as JUnit runs the other test class it calls the method under "@BeforeClass" annotation and runs the initialization code again in spite of the initialization check there.

like image 312
Prerak Tiwari Avatar asked Feb 09 '23 05:02

Prerak Tiwari


1 Answers

You can use a class rule:

public class ServiceInitializer extends ExternalResource {
  public static final TestRule INSTANCE = new ServiceInitializer();
  private final AtomicBoolean started = new AtomicBoolean();

  @Override protected void before() throws Throwable {
    if (!started.compareAndSet(false, true)) {
      return;
    }
    // Initialization code goes here
  }

  @Override protected void after() {
  }
}

Then you can use this in your test by using the @ClassRule annotation:

@RunWith(PowerMockRunner.class)
class BaseTest{
  @Rule
  public PowerMockRule powerMockRule = new PowerMockRule();
  @ClassRule
  public static final TestRule serviceInitializer = ServiceInitializer.INSTANCE;

  @Before
  public final void preTest() {
    // some code
  }

  @After
  public final void postTest() {
    //some code
  }
}

Edit: PowerMockRunner apparently doesn't support @ClassRule, so I switched the test to use PowerMockRule. You can read more about it from here. I personally prefer rules over custom runners anyway.

like image 120
NamshubWriter Avatar answered Feb 13 '23 23:02

NamshubWriter