接口的Mock测试及Mockito使用

参考链接

1.Mock测试的目的两个:(1)验证方法调用;(2)指定某个方法的返回值,或者是执行特定的动作

2.所谓的mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到两大目的

  1. 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等

  2. 指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作

3.  (1)UserManager mockUserManager = Mockito.mock(UserManager.class); 需要我们创建了一个mock对象;

    (2)我们必须在调用 loginPresenter.login() 之前,把 mUserManager 引用换成 mockUserManager 所引用的mock对象。最简单的办法,就是加一个setter:

public class LoginPresenter {

    private UserManager mUserManager = new UserManager();

    public void login(String username, String password) {
        if (username == null || username.length() == 0) return;
        if (password == null || password.length() < 6) return;

        mUserManager.performLogin(username, password);
    }

    public void setUserManager(UserManager userManager) {  //<==
        this.mUserManager = userManager;
    }

}

写出来的测试代码如下:

@Test
public void testLogin() throws Exception {
    UserManager mockUserManager = Mockito.mock(UserManager.class);
    LoginPresenter loginPresenter = new LoginPresenter();
    loginPresenter.setUserManager(mockUserManager);  //<==

    loginPresenter.login("xiaochuang", "xiaochuang password");

    Mockito.verify(mockUserManager).performLogin("xiaochuang", "xiaochuang password");
}

4.验证一个对象的某个method得到调用的方法:

   Mockito.verify(mockUserManager).performLogin("xiaochuang", "xiaochuang password");

   Mockito的静态方法 :对于调用次数的验证,除了可以验证固定的多少次,还可以验证最多,最少从来没有等等,方法分别 是: atMost(count),    atLeast(count), never() 等等。


5. 指定mock对象的某些方法的行为:  指定某个方法的返回值,或者是执行特定的动作

(1)

Mockito.verify(mockUserManager).performLogin(Mockito.anyString(), Mockito.anyString());

LoginPresenter 的 login 方法是如下:

public void login(String username, String password) {
    if (username == null || username.length() == 0) return;
    //假设我们对密码强度有一定要求,使用一个专门的validator来验证密码的有效性
    if (mPasswordValidator.verifyPassword(password)) return;  //<==

    mUserManager.performLogin(null, password);
}

这种指定mock对象的某个方法,让它返回特定值的写法如下:

Mockito.when(mockObject.targetMethod(args)).thenReturn(desiredReturnValue);

//先创建一个mock对象
PasswordValidator mockValidator = Mockito.mock(PasswordValidator.class);

//当调用mockValidator的verifyPassword方法,同时传入"xiaochuang_is_handsome"时,返回true
Mockito.when(mockValidator.verifyPassword("xiaochuang_is_handsome")).thenReturn(true);
    
//当调用mockValidator的verifyPassword方法,同时传入"xiaochuang_is_not_handsome"时,返回false
Mockito.when(validator.verifyPassword("xiaochuang_is_not_handsome")).thenReturn(false);
//当调用mockValidator的verifyPassword方法时,返回true,无论参数是什么
Mockito.when(validator.verifyPassword(anyString())).thenReturn(true);

(2)

指定一个方法执行特定的动作,这个功能一般是用在目标的方法是void类型的时候:

LoginPresenter 的 login() 方法:

public void loginCallbackVersion(String username, String password) {
    if (username == null || username.length() == 0) return;
    //假设我们对密码强度有一定要求,使用一个专门的validator来验证密码的有效性
    if (mPasswordValidator.verifyPassword(password)) return;

    //login的结果将通过callback传递回来。
    mUserManager.performLogin(username, password, new NetworkCallback() {  //<==
        @Override
        public void onSuccess(Object data) {
            //update view with data
        }

        @Override
        public void onFailure(int code, String msg) {
            //show error msg
        }
    });
}

我们想让 mUserManager 直接调用传入的 NetworkCallback 的 onSuccess 或 onFailure 方法。这种指定mock对象执行特定的动作的写法如下:

Mockito.doAnswer(desiredAnswer).when(mockObject).targetMethod(args); 传给 doAnswer() 的是一个 Answer 对象,我们想要执行什么样的动作,就在这里面实现

 Mockito.doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        //这里可以获得传给performLogin的参数
        Object[] arguments = invocation.getArguments();

        //callback是第三个参数
        NetworkCallback callback = (NetworkCallback) arguments[2];
        
        callback.onFailure(500, "Server error");
        return 500;
    }
}).when(mockUserManager).performLogin(anyString(), anyString(), any(NetworkCallback.class));
当调用 mockUserManager 的 performLogin 方法时,会执行answer里面的代码,我们上面的例子是直接调用传入的 callback 的 onFailure 方法,同时传给 onFailure 方法500和"Server error"。

自己的实例:采用第5点方法(1):

// 根据客户编号修改客户状态
    @Test
    public void updateCustomerStatusByCustomerNo(){
        String traceLogId = "110";
        String customerNo = "100001";
        CustomerBaseInfoReqDTO reqDTO = new CustomerBaseInfoReqDTO();
        reqDTO.setCustomerNo(customerNo);
        reqDTO.setUpdatedAt(new Date());
        reqDTO.setUpdatedBy("nazi");
        reqDTO.setStatus(CustBaseInfoStatus.CLOSE.getCode());

        Mockito.when(customerBaseInfoBiz.updateCustomerStatusByCustomerNo(Mockito.any(CustomerBaseInfoReqDTO.class))).thenReturn(Boolean.TRUE);
        Result result = customerBaseInfoService.updateCustomerStatusByCustomerNo(reqDTO, traceLogId);
        Assert.assertTrue(result.isSuccess());
        System.out.println("----------------------分隔线--------------------------");
        Mockito.when(customerBaseInfoBiz.updateCustomerStatusByCustomerNo(
                Mockito.any(CustomerBaseInfoReqDTO.class))).thenThrow(BizServerException.class);
        result = customerBaseInfoService.updateCustomerStatusByCustomerNo(reqDTO, traceLogId);
        Assert.assertFalse(result.isSuccess());
        System.out.println("----------------------分隔线--------------------------");
        Mockito.when(customerBaseInfoBiz.updateCustomerStatusByCustomerNo(
                Mockito.any(CustomerBaseInfoReqDTO.class))).thenThrow(NullPointerException.class);
        result = customerBaseInfoService.updateCustomerStatusByCustomerNo(reqDTO, traceLogId);
        Assert.assertFalse(result.isSuccess());
    }
 // 根据客户号查询客户账户信息
    @Test
    public void findCustAcctByCustomerNo(){
        List resDTOList = new ArrayList<>();
        Mockito.when(customerAccountManager.queryByCustomerNo(Mockito.any())).thenReturn(resDTOList);
        String customerNo = "0000000000020005";
        Result> result = customerInfoQueryService.findCustAcctByCustomerNo(customerNo,"110");
        Assert.assertTrue(result.isSuccess());
    }

Spy

目的:除非指定,否者调用这个对象的默认实现,同时又能拥有验证方法调用的功能

相异点:

spy与mock的唯一区别就是默认行为不一样:spy对象的方法默认调用真实的逻辑,mock对象的方法默认什么都不做,或直接返回默认值
//假设目标类的实现是这样的
public class PasswordValidator {
    public boolean verifyPassword(String password) {
        return "xiaochuang_is_handsome".equals(password);
    }
}

@Test
public void testSpy() {
    //跟创建mock类似,只不过调用的是spy方法,而不是mock方法。spy的用法
    PasswordValidator spyValidator = Mockito.spy(PasswordValidator.class);

    //在默认情况下,spy对象会调用这个类的真实逻辑,并返回相应的返回值,这可以对照上面的真实逻辑
    spyValidator.verifyPassword("xiaochuang_is_handsome"); //true
    spyValidator.verifyPassword("xiaochuang_is_not_handsome"); //false
    
    //spy对象的方法也可以指定特定的行为
    Mockito.when(spyValidator.verifyPassword(anyString())).thenReturn(true);
    
    //同样的,可以验证spy对象的方法调用情况
    spyValidator.verifyPassword("xiaochuang_is_handsome");
    Mockito.verify(spyValidator).verifyPassword("xiaochuang_is_handsome"); //pass
}

你可能感兴趣的:(JAVA,WEB)