如何使用mockito存根同一类的私有方法的返回值

Raj*_*war 7 java junit unit-testing mockito powermockito

我正在研究基于 spring 的项目并使用 JUnit + Mockito 编写单元测试用例。我在将布尔值存根到同一测试类的私有方法时遇到问题(在将访问级别更改为公共后,我仍然无法存根布尔值)。

下面的代码片段显示了相同问题的模拟

class ABC {

    public String method1(User userObj){
        String result = "";

        if(!isValidUser(userObj.getSessionID())){
            return "InvalidUser";
        } else {
           // execute some logic
        }

        return result;
    }


    private boolean isValidUser(String sessionId) {
        // Here it calls some other class to validate the user 
        if (sessionId == null || UserSessionPool.getInstance().getSessionUser(sessionId) == null) {
            return false;
        } else {
            return true;
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

在这里,我想为method1()编写一个测试用例。在 ABC 类中,我有一个方法被调用isValidUser(),它通过查看保存所有登录使用的详细信息的全局会话池来帮助识别会话中的用户UserSessionPool.getInstance().getSessionUser(sessionId)

在测试方法 1() 时,当测试控制器触发时,isValidUser(userObj.getSessionID())我想trueisValidUser()方法返回,以便我可以继续测试其余的实现逻辑。

到目前为止,我已经尝试使用 spy 和模拟对象来调用该isValidUser()方法并尝试返回 true 但没有任何效果。

使用 PowerMockito

PowerMockito.doNothing().when(spyed_ABC_ClassObject, "isValidUser", true);
Run Code Online (Sandbox Code Playgroud)

或者

PowerMockito.doReturn(true).when(cntrl, "isValidUser", Mockito.anyString());
Run Code Online (Sandbox Code Playgroud)

使用白盒

Whitebox.invokeMethod(spyed_ABC_ClassObject, "isValidUser", Mockito.anyString());
Run Code Online (Sandbox Code Playgroud)

使用 Mockito.when

when(spyed_ABC_ClassObject.isValidUser(Mockito.anyString())).thenReturn(true);
Run Code Online (Sandbox Code Playgroud)

或者

Mockito.doNothing().when(spyed_ABC_ClassObject).isValidUser(Mockito.anyString());
Run Code Online (Sandbox Code Playgroud)

Gho*_*ica 6

另一个答案是:修复您的设计,而不是求助于 PowerMock 的大锤子。

是的,PowerMock 允许您模拟静态方法。但是你应该明白:静态是好的 OO 设计中的一个异常。只有当你有很好的理由时才使用它。因为它会导致您的类之间的紧密耦合,令人惊讶的是:它破坏了您编写合理单元测试的能力。是的,PowerMock 有效;但有时,事实并非如此。当你的班级增长,你“静态地”做越来越多的事情,因为,你知道,PowerMock 会完成这项工作......在某些时候为奇怪的失败做好准备,这可能需要几个小时才能找到;永远不会在您的生产代码中发现真正的错误。

所以,考虑一个替代方案:

  1. 不要使用静态方法调用。如果周围有一些您无法触及的静态方法;考虑围绕它构建一个小界面。
  2. 相反:使用依赖注入并简单地将实现某些接口的对象传递到您的生产代码中。因为您可以在不需要 PowerMock(ito) 的情况下模拟此类对象。

从这个意义上说:您只是创建了难以测试的代码。现在您打算使用 PowerMock 修复该问题。另一种方式(在我看来更合理)是首先学习如何编写可测试的代码。是一个很好的起点。


Rav*_*ala 2

你能尝试一下吗?

@Before
public void setUp() {
    UserSessionPool mockConnectionPool = Mockito.mock(UserSessionPool.class);
}

@Test
public void testName() throws Exception {
    //given
    PowerMockito.mockStatic(UserSessionPool.class);
    BDDMockito.given(UserSessionPool.getInstance()(...)).willReturn(mockConnectionPool);
    Mockito.when(mockConnectionPool.getSessionUser(Mockito.anylong())).thenReturn(something);


    //then
    PowerMockito.verifyStatic();

}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。编码愉快!