简体   繁体   中英

Powermock : Mocked method still called

First of all, please know that I've searched SO before asking this question, but I was unable to find a satisfying answer.

I'm using JUnit4 and Powermock 1.5.5 (with mockito 1.9.5)

My problem is the following : in my unit tests, I need to mock a static method in a class I can't modify. I only want to mock one method, and not the whole class, so I went for a spy.

Here's what I have so far :

[...]
import static org.mockito.Matchers.*;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(JUnitParamsRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext-test.xml"},
    loader=MockWebApplicationContextLoader.class)
@MockWebApplication(name="my-app")
@PrepareForTest(value = {
    Role.class
})
public class MyTest {

    @Rule
    public PowerMockRule powerMockRule = new PowerMockRule();

    @Before
    public void setUp() throws Exception {
        initSpring();
        mockRoleServices();
    }

    private void mockRoleServices() throws Exception {
        spy(Role.class);
        RoleAnswer roleAnswer = new RoleAnswer(RoleEnum.ADMIN);
        when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
            .then(roleAnswer);
    }

    private class RoleAnswer implements Answer<Boolean> {

        private RoleEnum roleEnum;

        private RoleAnswer(RoleEnum roleEnum) {
            this.roleEnum = roleEnum;
        }

        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            return getRenderRequest().getUserRole() != null &&
                    getRenderRequest().getUserRole().equals(roleEnum);
        }
    }
}

Here's the problem : the method Role.hasAdministratorRole() is called instead of being mocked

Here's what I tried so far :

  • Using mockStatic(Role.class) instead of the spy() method. As expected, all methods are mocked, so I end up getting an NPE before Role.hasAdministratorRole() is called
  • Doing something like doAnswer(...).when(...) . I get a runtime error with powermock telling me my mock is not complete (which actually confirms that something's wrong either with my code or with the lib itself)
  • Trying to declare the method by its name rather than calling it directly : when(Role.class, "hasAdministratorRole", long.class, long.class, long.class) . Same behavior
  • A bunch of other things I don't recall anymore.

Your help will be greatly appreciated. Thanks !

EDIT : Thanks to SrikanthLingala's answer, I was able to pinpoint the problem.

This didn't work :

when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
    .thenAnswer(roleAnswer);

but this did :

doAnswer(roleAnswer).when(Role.class, "hasSiteAdministratorRole",
    anyLong(), anyLong(), anyLong());

So switching then when() and the answer() worked

As I do not have all of your implementations, I setup some dummy implementations and made a similar setup like yours. The below code works fine for me.

import static junit.framework.Assert.assertTrue;

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

@RunWith(PowerMockRunner.class)
@PrepareForTest(value = {
    Role.class
})
public class RoleTest {

    @Test
    public void mockRoleServices() throws Exception {
        PowerMockito.spy(Role.class);
        PowerMockito.doAnswer(new RoleAnswer(RoleEnum.ADMIN)).when(Role.class, "hasAdministratorRole", Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong());

        Role.printOut();

        assertTrue(Role.hasAdministratorRole(1, 1, 1));
    }

    private class RoleAnswer implements Answer<Boolean> {

        private RoleEnum roleEnum;

        private RoleAnswer(RoleEnum roleEnum) {
            this.roleEnum = roleEnum;
        }

        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            return true;
        }
    }
}

Dummy Role class:

public class Role {

    public static Boolean hasAdministratorRole(long a, long b, long c) {
        System.out.println("Inside hasAdministratorRole");
        return a + b + c < 0;
    }

    public static void printOut() {
        System.out.println("Inside Printout");
    }

}

My test case does not printout Inside hasAdministratorRole , but prints out Inside Printout

Hope this helps

Glad you have solved your issue, this just a warning for everyone else having a similar issue.

Project setup:

  • Powermock 1.5.5
  • Mockito 1.9.5
  • TestNG 6.8.8

Powermock is not taking into account mocks/spies created in a method annotated with @BeforeTest

Eg:

@BeforeTest
public void setup(){
    testee = mock(AClass.class);
}

It gets discarded and then it is entering the mocked method instead of returning the expected result OR throwing all kinds of strange exceptions. When moved to a common test method, it suddenly starts working:

@Test
public void test(){
    AClass testee = mock(AClass.class);
    ....
}

Possibly it is a bug.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM