【问题标题】:How to stub return value for the private method of same class using mockito如何使用 mockito 为同一类的私有方法存根返回值
【发布时间】:2017-05-12 08:22:51
【问题描述】:

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

下面的代码sn-p显示了相同问题的模拟

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

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

在测试method1()时,测试控制器触发isValidUser(userObj.getSessionID())的那一刻我想从isValidUser()方法中返回true,这样我就可以继续测试其余的实现逻辑了。

到目前为止,我已经尝试了以下方法,使用 spy 和 mocked object 来调用 isValidUser() 方法并尝试返回 true,但没有任何效果。

使用 PowerMockito

PowerMockito.doNothing().when(spyed_ABC_ClassObject, "isValidUser", true);

PowerMockito.doReturn(true).when(cntrl, "isValidUser", Mockito.anyString());

使用白盒

Whitebox.invokeMethod(spyed_ABC_ClassObject, "isValidUser", Mockito.anyString());

使用 Mockito.when

when(spyed_ABC_ClassObject.isValidUser(Mockito.anyString())).thenReturn(true);

Mockito.doNothing().when(spyed_ABC_ClassObject).isValidUser(Mockito.anyString());

【问题讨论】:

    标签: java unit-testing junit mockito powermockito


    【解决方案1】:

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

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

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

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

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

    【讨论】:

      【解决方案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();
      
      }
      

      希望这会有所帮助。快乐编码!

      【讨论】:

      • Ravindra Ranwala 感谢您的回答,但在执行 BDDMockito.given(UserSessionPool.getInstance()(...)).willReturn(mockConnectionPool); 时出现异常,例如 MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'.
      • 你能告诉我 BDDMockito 方法中的 (...) 是什么
      • 我已经评论了BDDMockito.given(UserSessionPool.getInstance()).willReturn(mockConnectionPool) 这行代码,我可以通过一些简单的代码更改来做到这一点。感谢您的帮助
      猜你喜欢
      • 2014-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      相关资源
      最近更新 更多