【问题标题】:Powermock : Mocked method still calledPowermock:仍然调用模拟方法
【发布时间】:2014-06-25 19:57:28
【问题描述】:

首先,请知道我在问这个问题之前已经搜索过 SO,但我找不到令人满意的答案。

我正在使用 JUnit4 和 Powermock 1.5.5(使用 mockito 1.9.5)

我的问题如下:在我的单元测试中,我需要在一个我无法修改的类中模拟一个静态方法。我只想模拟一个方法,而不是整个班级,所以我去找了一个间谍。

这是我目前所拥有的:

[...]
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);
        }
    }
}

问题是:Role.hasAdministratorRole() 方法被调用而不是被模拟

这是我迄今为止尝试过的:

  • 使用mockStatic(Role.class) 代替spy() 方法。正如预期的那样,所有方法都被模拟了,所以我最终在调用 Role.hasAdministratorRole() 之前得到了一个 NPE
  • doAnswer(...).when(...) 这样的事情。我收到 powermock 运行时错误,告诉我我的模拟不完整(这实际上证实了我的代码或 lib 本身有问题)
  • 尝试通过名称声明方法而不是直接调用它:when(Role.class, "hasAdministratorRole", long.class, long.class, long.class)。相同的行为
  • 还有一堆我不记得了。

您的帮助将不胜感激。 谢谢!

编辑:感谢 SrikanthLingala 的回答,我能够查明问题所在。

这不起作用:

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

但是这样做了:

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

所以切换然后when()answer() 工作

【问题讨论】:

  • 另外,我注意到我试图模拟的类在类路径中的一个 jar 中(即不直接在类路径中)。这可能是相关的吗?
  • 可能是因为你没有使用 PowerMockRunner 运行测试?
  • 其他模拟工作,因为我正在使用 PowerMockRule。但无论如何,我测试了它,我得到了完全相同的输出:(

标签: java unit-testing junit4 powermock


【解决方案1】:

由于我没有您的所有实现,因此我设置了一些虚拟实现并进行了与您类似的设置。下面的代码对我来说很好。

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;
        }
    }
}

虚拟角色类:

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");
    }

}

我的测试用例没有打印出Inside hasAdministratorRole,而是打印出Inside Printout

希望对你有帮助

【讨论】:

  • 非常感谢您花时间测试它。我能够让它直接在我的类路径中使用类(即不在 jar 中)。你能试着把你的虚拟类放在一个罐子里,然后重新测试吗?我开始认为问题出在于此。
  • 即使从罐子里也能正常工作。
  • 感谢您的回答,我已经成功了。我编辑了我的问题以添加答案,但我真的不明白为什么会这样。你有提示吗?再次感谢您的宝贵帮助
【解决方案2】:

很高兴您解决了您的问题,这只是对遇到类似问题的其他人的警告。

项目设置:

  • Powermock 1.5.5
  • Mockito 1.9.5
  • TestNG 6.8.8

Powermock 没有考虑在使用 @BeforeTest 注释的方法中创建的模拟/间谍

例如:

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

它被丢弃,然后进入模拟方法,而不是返回预期结果或抛出各种奇怪的异常。当转移到一个常见的测试方法时,它突然开始工作了:

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

这可能是一个错误。

【讨论】:

猜你喜欢
  • 2015-11-04
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
  • 1970-01-01
相关资源
最近更新 更多