Search code examples
junitmockitojunit4powermockpowermockito

Testing that static method inside void method has been called once


I need some help with testing. Having the following method:

    @PrePersist
    public void prePersist(Tag tag) {

        if (tagService.listUserTags(tag.getUser())
                .size() > Constants.Tags.maxPerUser) {
            TaskUtils.createTask(url, param);
        }
    }

I want to test that TaskUtils.createTask() is called once, but I don't want the code inside it to be executed. I have tried like this:

        @Test
        @PrepareForTest(TaskUtils.class)
        public void testPrePersistMethodWhenTagCountOverLimit() {
            [...]
            when(tags.size()).thenReturn(Constants.Tags.maxPerUser + 1);
            when (tagService.listUserTags(tag.getUser())).thenReturn(tags);

            PowerMockito.mockStatic(TaskUtils.class);
            PowerMockito.doNothing().when(TaskUtils.class, "createTask", Mockito.any(String.class), Mockito.any(String.class));                                            

            Method method = ClassUtils.getMethodWithAnnotation(TagListener.class, PrePersist.class);
            method.invoke(tagListener, tag); //here the prePersist method is called

            PowerMockito.verifyStatic( Mockito.times(1));

        }

But the method TaskUtils.createTask() is actually executed in spite of doNothing. Part of the stack trace:

java.lang.NullPointerException
    at fi.util.TaskUtils.createTask(TaskUtils.java:90)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1873)
    at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:773)
    at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:753)
    at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:466)
    at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:106)
    at fi.intra.test.domain.listener.TestTagListener.testPrePersistMethodWhenTagCountOverLimit(TestTagListener.java:92)

Any ideas?


Solution

  • The following works and should be equivalent to your case:

    I used Gradle for building, and added the following dependency:

    testCompile group: 'org.powermock', name: 'powermock-mockito-release-full', version: '1.6.4'

    The test

    package sojava.mocking;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    import static org.assertj.core.api.Assertions.assertThat;
    import static org.mockito.Mockito.times;
    import static org.powermock.api.mockito.PowerMockito.*;
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(MyData.class)
    public class PowerMockitoTests {
    
        @Test
        public void static_method_when_mocked_does_nothing() throws Exception {
            int amount = 123;
    
            // Arrange
            mockStatic(MyData.class);
            doNothing().when(MyData.class, "increment", amount);
    
            // Action
            new MyDataWrapper().increment(amount);
            verifyStatic(times(1));
            MyData.increment(amount);
    
            // Assert
            assertThat(MyData.getCount()).isEqualTo(0);
        }
    }
    

    Have you seen this code?

    new MyDataWrapper().increment(amount);
    verifyStatic(times(1));
    MyData.increment(amount);
    

    This is awkward but this is how it works. Want to test that a static method was called a number of times? Then you call that method, then call verifyStatic(), then call that static method again. The last call will trigger the check.

    Class using the static method

    package sojava.mocking;
    
    public class MyDataWrapper {
        public void increment(int amount) {
            MyData.increment(amount);
        }
    }
    

    Class containing the static method

    package sojava.mocking;

    public class MyData {
    
        private static int count = 0;
    
        private MyData() {
        }
    
        public static void increment(int amount) {
            count += amount;
        }
    
        public static int getCount() {
            return count;
        }
    }
    

    More samples: more samples are located on their Github page on the tests folder.