拦截私有方法在公共方法中返回的对象

时间:2017-02-20 11:43:06

标签: java junit mockito junit4 powermock

我需要对方法进行单元测试,我想模拟行为,以便我可以在方法中测试代码的必要部分。

为此,我想访问我试图测试的方法中的私有方法返回的对象。我创建了一个示例代码,以便基本了解我要实现的目标。

Main.class

Class Main {
  public String getUserName(String userId) {
    User user = null;
    user = getUser(userId);
    if(user.getName().equals("Stack")) {
      throw new CustomException("StackOverflow");
    }

    return user.getName();

 }

 private User getUser(String userId) {
  // find the user details in database
  String name = ""; // Get from db
  String address = ""; // Get from db
  return new User(name, address);
 }
}

测试类

@Test (expected = CustomException.class)
public void getUserName_UserId_ThrowsException() {
  Main main = new Main();
  // I need to access the user object returned by getUser(userId)
  // and spy it, so that when user.getName() is called it returns Stack
  main.getUserName("124");
}  

3 个答案:

答案 0 :(得分:1)

访问私有的方法只有两种:

  1. 使用反射
  2. 扩展范围
  3. 可能在等待Java 9使用新的范围机制?
  4. 我会将范围修饰符从私有范围更改为包范围。使用反射对于重构是不稳定的。如果您使用PowerMock等帮助程序并不重要。它们只会减少围绕反射的锅炉板代码。

    但最重要的一点是你不应该在whitbox测试中测试太深。这可能会使测试设置爆炸。尝试将代码切成小块。

    用户对象中“getUserName”方法所需的唯一信息是名称。它将验证名称并抛出异常或返回它。因此,没有必要在测试中引入User-object。

    所以我的建议是你应该将从User-object中取出名称的代码提取到一个单独的方法中并制作这个方法包的范围。现在不需要仅仅使用主对象来模拟用户对象。但是该方法的最小信息可以正常工作。

    class Main {
    
        public String getUserName(String userId) {
            String username = getUserNameFromInternal(userId);
            if (userName.equals("Stack")) {
                throw new CustomException("StackOverflow");
            }
            return user.getName();
        }
    
        String getUserNameFromInternal(String userId) {
            User user = getUser(userId);
            return user.getName();
        }
    
        ...
    
    }
    

    测试:

    @Test (expected = CustomException.class)
    public void getUserName_UserId_ThrowsException() {
      Main main = Mockito.mock(new Main());
      Mockito.when(main.getUserNameInternal("124")).thenReturn("Stack");
      main.getUserName("124");
    }
    

答案 1 :(得分:1)

您的私有方法中呼叫new的问题。

答案不是转向PowerMock;或者改变该方法的可见性。

合理的答案是"提取"依赖于"给我一个User对象的东西"进入自己的班级;并为您的" Main"提供该课程的实例。类。因为那样你就可以简单地模仿那个"工厂"宾语;并让它做你想做的任何事情。

含义:您当前的代码很难测试。您没有解决由此引起的问题,而是花时间学习如何编写易于测试的代码;例如,将这些videos作为起点。

鉴于您的最新评论:当您处理遗留代码时,您真的希望使用PowerMockito。要理解的关键部分:你不要嘲笑"私人方法;你宁愿考虑嘲笑对new User()的号召;如here所述。

答案 2 :(得分:0)

您可以使用PowerMock的mockPrivate,但我不推荐它。 如果你有这样的问题,通常意味着你的设计很糟糕。 为什么不保护方法?