5

I want to verify that a public static void method has been called.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ConsoleLog.class})
public class AdContentDataUnitTest {

    @Before
    public void setUp() throws Exception {
        PowerMockito.mockStatic(ConsoleLog.class);
    }

    @Test
    public void adContentData_sendTrackingEvent_noUrl() throws Exception {
        mAdContentData = spy(mAdContentData);

        // PowerMockito.doNothing().when(ConsoleLog.class);

        verifyStatic();
        mAdContentData.sendTrackingEvent("event1");
        //verifyStatic();
    }
}

sendTrackingEvent will be invoked, and the ConsoleLog.v(String, String) will be called. I can see in debug that the static method is called, but the following log appear and the test fail:

Wanted but not invoked com.example.logger.ConsoleLog.v(
    "AdContentData",
    "sendTrackingEvent: event event1 does not exist."
);

I've tried to add the verifyStatic after but same log, and if I remove the first verify, nothing is checked. If I mock the whole ConsoleLog class the error Unfinished stubbing detected here: [...] PowerMockitoCore.doAnswer appear.

Does anyone know how to do it properly?

Hugo Gresse
  • 17,195
  • 9
  • 77
  • 119

1 Answers1

3

Do anyone know how to do it properly?

Yes. Don't do it at all.

Let's say you have a class that calls a static method like this:

class Person {
    private final int id;

    Person() {
        id = IdGenerator.gen();
    }
}

Extract the static call to a non-static method:

class Person {
    private final int id;

    Person() {
        id = generateId();
    }

    protected int generateId() {
        return IdGenerator.gen();
    }
}

Now you can write a test, overriding the extracted method:

    final int id = 1;
    Person person = new Person() {
        @Override
        protected int generateId() {
            return id;
        }
    };

    // test with person, knowing we control id

But the ideal solution is actually to refactor the code under test to not use such static calls at all, but dependency injection.

janos
  • 120,954
  • 29
  • 226
  • 236
  • this is a solution but it reduce the performance as we need to call one method more (I'm on Android and perf matters) – Hugo Gresse May 13 '16 at 07:54
  • The compiler may very well inline such method calls. Are you sure it makes a significant perf difference? Have you measured it? I forgot to mention the ideal solution is to refactor to code under test to not use static calls but use dependency injection – janos May 13 '16 at 07:59
  • well, the `ConsoleLog` is a wrap class of http://developer.android.com/reference/android/util/Log.html – Hugo Gresse May 13 '16 at 08:05
  • I see this is on Android, so maybe you cannot inject it. So you can ignore my suggestion about dependency injection. But the "extract and override" technique suggestion still stands. A single indirection is unlikely to make a difference in terms of perf, and it's reasonable to *presume innocent until proven guilty* (benchmark measurements showing a non-negligible difference) – janos May 13 '16 at 08:13