【问题标题】:Java Mockito - verify method called with reference type parameterJava Mockito - 使用引用类型参数调用的验证方法
【发布时间】:2020-07-30 00:02:46
【问题描述】:

我在验证某些方法应该使用特定参数调用时使用 Mockito 是新手,而所有值类型参数(int、String、enum 等)都可以验证,但引用/类类型参数似乎不是,这是一个例子

// my actual class
public class MyActualClass {
   public void processRequest() {
       User curUser = MyUtils.getUserFromOtherPlace(UserType.ADMIN);
       processAnotherRequest(1, "address", curUser);
   }
   public void processAnotherRequest(int userId, String address, User user) { ... }
}
public static class MyUtils{
   public static getUserFromOtherPlace(UserType userType) {
       User newUser = new User();
       if (userType == UserType.ADMIN) {
          newUser.setAccess(1);
       }
       //...
       return newUser
   }
}

// my test class
public class MyActualClassTest{
   @Mock
   private MyActualClass myActualClass;

   @Test
   public void testIfMethodBeingCalledCorrectly() {
      User adminUser = new User();
      adminUser.setAccess(1);
      doCallRealMethod().when(myActualClass).processRequest();
      myActualClass.processRequest();
      verify(myActualClass).processAnotherRequest(1, "address", adminUser);
   }
}

我知道这可能是因为我的测试方法中设置的 adminUser 与通过我的实际方法 getUserFromOtherPlace -> MyUtils.getUserFromOtherPlace 生成的引用对象不同,我还尝试用我的静态模拟返回对象方法如

// tried 1
when(MyUtils.getUserFromOtherPlace(UserType.ADMIN).thenReturn(adminUser);  // this throws error like "You cannot use argument matchers outside of verification or stubbing", and suggest using eq()
// tried 2
when(MyUtils.getUserFromOtherPlace(eq(UserType.ADMIN)).thenReturn(adminUser); //this throws NullPointer exception in getUserFromOtherPlace when check the input enum parameter "userType"

那么我怎样才能将引用对象传递给我的入口方法并在这里模拟它作为我的内部方法的返回值呢?顺便说一句,如果我的方法只包含值类型参数,它会工作...

【问题讨论】:

    标签: java unit-testing nullpointerexception mockito reference-type


    【解决方案1】:

    所以为了模拟你的静态方法,你需要:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ MyUtils.class })
    
    //your test class here
    
    @Before
    public void setup() {
        PowerMockito.mockStatic(MyUtils.class);
        when(MyUtils.getUserFromOtherPlace(UserType.ADMIN).thenReturn(adminUser);
    }
    

    但如果有其他选择,我总是不喜欢模拟静态类,所以也许你可以尝试一个参数捕获器:

    //test class
    
    @Captor
    private ArgumentCaptor<User> captor;
    
    //your test
    @Test
    public void testIfMethodBeingCalledCorrectly() {
        doCallRealMethod().when(myActualClass).processRequest();
        myActualClass.processRequest();
        verify(myActualClass, times(1)).processAnotherRequest(1, "address", 
            captor.capture());
        Assert.assertEquals(1, captor.getValue().getAccess());
    }
    

    【讨论】:

      【解决方案2】:

      首先,除非不使用 powermock,否则无法模拟静态方法。相反,您可以将 User 对象作为参数传递给 processRequest。

      public void processRequest(User curUser) {
          processAnotherRequest(1, "address", curUser);
      }
      
      public void processAnotherRequest(int userId, String address, User user) {
          //...
      }
      

      然后,您可以在测试代码中使用对象引用。

      User adminUser = MyUtils.getUserFromOtherPlace(UserType.ADMIN);
      adminUser.setAccess(1);
      doCallRealMethod().when(myActualClass).processRequest(adminUser);
      myActualClass.processRequest(adminUser);
      verify(myActualClass).processAnotherRequest(1, "address", adminUser);
      

      【讨论】:

      • 好吧,我无法更改我的测试方法的签名,但我可以将我的静态类和方法替换为非静态的,在我的测试方法中,创建一个 MyUtils 类的新实例,但是,这并不能解决我的问题,因为在我的测试方法中启动的类实例 MyUtils 与我在测试类中为返回对象模拟的实例不同
      猜你喜欢
      • 2017-02-18
      • 2021-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多