mock学习总结

JAVA学习网 2017-10-15 00:00:02

Moke测试学习总结:

 

被测试代码:

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 class LoginPresenterTest {

 

    @Test

    public void testLogin() throws Exception {

        LoginPresenter loginPresenter = new LoginPresenter();

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

 

        //验证LoginPresenter里面的mUserManager的performLogin()方法得到了调用,同时参数分别是“xiaochuang”、“xiaochuang‘s password”

        ...

    }

}

 

问题1:么验证 LoginPresenter 里面的 mUserManager 的 performLogin() 方法得到了调用,以及它的参数是正确性呢?

 下面开始mock的学习

Moko概念:

Mock的概念,其实很简单,我们前面也介绍过:所谓的mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到两大目的:

  1. 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等
  2. 指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作

验证开始:

 

试误1:

public class LoginPresenterTest {

 

    @Test

    public void testLogin() throws Exception {

        Mockito.mock(UserManager.class);

        LoginPresenter loginPresenter = new LoginPresenter();

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

 

        UserManager userManager = loginPresenter.getUserManager();

        Mockito.verify(userManager).performLogin("xiaochuang", "xiaochuang password");  //<==

    }

}

 

试误2:

public class LoginPresenterTest {

 

    @Test

    public void testLogin() throws Exception {

        UserManager mockUserManager = Mockito.mock(UserManager.class);  //<==

        LoginPresenter loginPresenter = new LoginPresenter();

       

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

 

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

    }

}

 

正确:

 

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");

}

 

第一种情况:

  1. 验证方法调用

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

 

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

类似 anyString ,还有 anyInt, anyLong, anyDouble 等等。 anyObject 表示任何对象, any(clazz) 表示任何属于clazz的对象。在写这篇文章的时候,我刚刚发现,还有非常有意思也非常人性化的 anyCollection,anyCollectionOf(clazz), anyList(Map, set), anyListOf(clazz) 等等。

 

  1. 指定mock对象的某些方法的行为

 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对象

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

同样的,你可以用 any 系列方法来指定"无论传入任何参数值,都返回xxx":

 

//当调用mockValidator的verifyPassword方法时,返回true,无论参数是什么

Mockito.when(validator.verifyPassword(anyString())).thenReturn(true);

 

2、我们想进一步测试传给 mUserManager.performLogin 的 NetworkCallback 里面的代码,

 

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

 

 

 

//假设目标类的实现是这样的

public class PasswordValidator {

    public boolean verifyPassword(String password) {

        return "xiaochuang_is_handsome".equals(password);

    }

}

 另外 spy的情况

@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

}

阅读(772) 评论(0)