Pradeep Gollakota
Pradeep Gollakota

Reputation: 2181

Static mocking with PowerMock and Mockito not working

I'm trying to verify that the Collections.shuffle() method was called in one of my classes. I read through the (little) documentation on PowerMock with Mockito and read through the other SO questions that dealt with this issue and didn't get a resolution.

@RunWith(PowerMockRunner.class)
@PrepareForTest(Collections.class)
public class MyTest {

    @Test
    public void testShuffle() {
        PowerMockito.mockStatic(Collections.class);
        PowerMockito.doCallRealMethod().when(Collections.class);
        Collections.shuffle(Mockito.anyListOf(Something.class));

        ClassToTest test = new ClassToTest();
        test.doSomething();

        PowerMockito.verifyStatic(); // Verify shuffle was called exactly once
        Collections.shuffle(Mockito.anyListOf(Something.class));
    }
}

public class ClassToTest {
    private final List<Something> list;
    // ...
    public void doSomething() {
        Collections.shuffle(list);
        // do more stuff
    }
}

Given the above code, I expect the unit test pass. However, the unit test fails as follows:

Wanted but not invoked java.util.Collections.shuffle([]);
Actually, there were zero interactions with this mock.

What am I doing wrong?

Thanks

EDIT: As per the suggestion below I tried the following, and I get the same error.

@RunWith(PowerMockRunner.class)
@PrepareForTest(Collections.class)
public class MyTest {

    @Test
    public void testShuffle() {
        PowerMockito.mockStatic(Collections.class);

        ClassToTest test = new ClassToTest();
        test.doSomething();

        PowerMockito.verifyStatic(); // Verify shuffle was called exactly once
        Collections.shuffle(Mockito.anyListOf(Something.class));
    }
}

Upvotes: 5

Views: 8174

Answers (2)

tmetten
tmetten

Reputation: 132

This is a rather old question, but I'd still like to clarify that the accepted answer is in fact incorrect. By executing the following code,

PowerMockito.mockStatic(Collections.class);
Collections.shuffle(Mockito.anyListOf(Something.class));

all verifies will always pass afterwards:

PowerMockito.verifyStatic(); // Verify shuffle was called exactly once
Collections.shuffle(Mockito.anyListOf(Something.class));

even if you do not call test.doSomething(); the provided test in the answer will still pass. The correct way to test this is to actually check if the items in the List have been sorted correctly.

Upvotes: 5

Christopher Roscoe
Christopher Roscoe

Reputation: 777

You can either mock/verify the java.util.Collections.shuffle([]) method or call the real implementation (with PowerMockito.doCallRealMethod()). But you can't do both.

If you remove

PowerMockito.doCallRealMethod().when(Collections.class);

the call will be verified and the test will pass.

https://powermock.googlecode.com/svn/docs/powermock-1.4.7/apidocs/org/powermock/api/mockito/PowerMockito.html#doCallRealMethod%28%29

This code works for me:

package test;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Collections.class)
public class MyTest {

    @Test
    public void testShuffle() {
        PowerMockito.mockStatic(Collections.class);
/*        PowerMockito.doCallRealMethod().when(Collections.class);  remove this line */
        Collections.shuffle(Mockito.anyListOf(Something.class));

        ClassToTest test = new ClassToTest();
        test.doSomething();

        PowerMockito.verifyStatic(); // Verify shuffle was called exactly once
        Collections.shuffle(Mockito.anyListOf(Something.class));
    }
}

class ClassToTest {
    private List<Something> list = new LinkedList<Something>();
    // ...
    public void doSomething() {
        Collections.shuffle(list);
        // do more stuff
    }
}
class Something {
}

Upvotes: 4

Related Questions