2

I have taken a reference of PowerMock from : Mock private method using PowerMockito and applied the same logic here. Also, I installed EMMA (open source tool) in eclipse/STS, but when I run the code I see zero % code coverage. why ?

public class MyClient {

    public void publicApi() {
        System.out.println("In publicApi");
        int result = 0;
        try {
            result = privateApi("hello", 1);
        } catch (Exception e) {
            //Assert.fail();
        }
        System.out.println("result : "+result);
        if (result == 20) {
            throw new RuntimeException("boom");
        }
    }

    private static int privateApi(String whatever, int num) throws Exception {
        System.out.println("In privateAPI");
        thirdPartyCall();
        int resp = 10;
        return resp;
    }

    private static void thirdPartyCall() throws Exception{
        System.out.println("In thirdPartyCall");
        //Actual WS call which may be down while running the test cases
    }
}

MyClientTest.java

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClient.class)
public class MyClientTest {

    @Test
    public void testPublicAPI() throws Exception {
        PowerMockito.mockStatic(MyClient.class);

        //PowerMockito.doReturn(10).when(MyClient.class, "privateApi", anyString(), anyInt());
        PowerMockito.when(MyClient.class,"privateApi", anyString(), anyInt()).thenReturn(anyInt());
    }
}

Actual Code Coverage: enter image description here

pom.xml

<dependencies>
        <!-- Power Mock -->
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>1.7.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>1.7.4</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4-rule-agent</artifactId>
            <version>1.7.4</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-core</artifactId>
            <version>1.7.4</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
Jeff Cook
  • 7,956
  • 36
  • 115
  • 186
  • You seem to prepare static methods for testing (i.e. by manipulating the byte code via `PowerMockito.mockStatic(...)` and the `@PrepareForTest(...)`), and I can see you are setting up test/mock behaviour (using PowerMockito's `when(...).thenReturn(...)`), but @user298396 is right - there doesn't seem to be anything in your test actually exercising/calling your class under test...? – Christian Aug 29 '18 at 18:35
  • PowerMock + ECLemma: broken coverage data. Get used to it. Either try cobertura, or (honestly, the better approach): learn how to write *easy to test* production code that can be tested without PowerMock(ito) byte code manipulation voodoo magic. – GhostCat Sep 03 '18 at 11:28

1 Answers1

-1

If you are constructing a Spy or Mock you are not invoking the actual code under test. The point of spies is to be able to verify() them, in order to check your code behaved correctly by invoking the right callbacks or methods. In the case of mocks the point is to steer code down a particular control flow path and also to verify() expected interactions with the mock.

Since your test case invokes the test method on a spy, it is therefore no wonder your code coverage is exactly 0%. If you were to verify your interactions with the mocked method, you'd probably find that none happened.

What you want to do instead is to setup your mocks but invoke the actual code under test 'the normal way'. The idea is to prime the execution environment, then invoke the tested method call 'normally', and finally observe what actually happened. That last bit consists of normal assertions on the produced output, verification of expected interactions (both that these took place, and also that these involved the expected arguments/values).

Change your test code:

MyClient classUnderTest = PowerMockito.spy(new MyClient());

To:

MyClient classUnderTest = new MyClient();

And watch the code coverage.

user268396
  • 11,576
  • 2
  • 31
  • 26
  • Take a look at your test code. As long as your unit under test is simply a spy you are simply not hitting your actual implementation, but rather whatever proxy the mocking/spying framework synthesises for you. So you get 0% code coverage. – user268396 Aug 28 '18 at 18:37
  • As for what the benefit of a mock is: to prime your execution environment, i.e. to simulate behaviour of the dependencies of your unit under test. You use mocks to ensure particular control flow branches are taken or not taken as may be desired for your test case. – user268396 Aug 28 '18 at 18:39
  • You should invoke the actual unit under test. Basically this line is wrong: `MyClient classUnderTest = PowerMockito.spy(new MyClient());` because that gives you a spy, not the actual unit under test. Remember: spies are not the actual code you want to test! – user268396 Aug 28 '18 at 18:42
  • Just construct your unit under test normally, like you would in your other non-testing code. – user268396 Aug 28 '18 at 18:42
  • Still it doesn't help. Could you please try to run this code at your end ? – Jeff Cook Aug 28 '18 at 18:49