Search code examples
javaunit-testingpowermockito

PowerMocking Static method within Class Under Test


I am currently working on implementing a unit test for our Exit Code Manager that were implemented using static methods. The problem that I encounter is how can I mock the executeExit, which calls System.exit(), method so that it would not terminate all the test.

I tried spying on the SampleClass however it still continue on exiting the program whenever I run the test. Another solution that I try is to mock the whole class and use the doCallRealMethod for the method under test. However, this solution it faulty because (1) class under test are not undergoing code coverage, and (2) it is somehow testing the mocked class instead of the real class under test. I also tried mocking the System.class but it is also not working.

All kinds of help are pretty much appreciated. THANKS!

Below is a sample code similar to our method structure.

public class SampleClass{

    public static void methodA(){
        //do something here
        executeExit();

    public static void executeExit(){
        //doing some stuff
        System.exit(exitCode);
    }
}

Below is a sample code of how I run my test:

@RunWith(PowerMockRunner.class)
@PrepareForTest(SampleClass)
public class SampleClassTest {

    @Test
    public void testMethodA(){
        PowerMockito.spy(SampleClass.class);
        PowerMockito.doNothing().when(SampleClass.class,"executeExit");

        SampleClass.methodA();
    }
}

Solution

  • I would test your code like this:

    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.contrib.java.lang.system.ExpectedSystemExit;
    import org.junit.runner.RunWith;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    @RunWith(PowerMockRunner.class)
    public class SampleClassTest {
    
        @Rule
        ExpectedSystemExit exit = ExpectedSystemExit.none();
    
        @Test
        public void testMethodA() {
    
            exit.expectSystemExitWithStatus(-1);
            SampleClass.methodA();
        }
    }
    

    You need following dependency

    <dependency>
        <groupId>com.github.stefanbirkner</groupId>
        <artifactId>system-rules</artifactId>
        <version>1.16.1</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>junit</groupId>
                <artifactId>junit-dep</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

    Or if you do not want to import that dependency you can do it like:

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ SampleClass.class })
    public class SampleClassTest {
    
    
        @Test
        public void testMethodA() {
    
            PowerMockito.spy(SampleClass.class);
            PowerMockito.doNothing().when(SampleClass.class);
            SampleClass.executeExit();
    
            SampleClass.methodA();
    
            PowerMockito.verifyStatic();
            SampleClass.executeExit();
    
        }
    }