如果想要检查被 Mock 的方法的入参是什么?这往往是很重要的。否则,入参不正确,怎么保证 Mock 的方法被正确调用了呢?

  假设,你要测试的方法依赖 UserDAO,因为 UserDAO 依赖数据库环境(虽然现在有基于内存存储和基于文件存储的轻便关系型数据库,使得在一些场景下,基于数据库的方法可以在 UT 中直接被测试,但在一些情况下,例如基于某种数据库特殊语法的操作,存储过程的操作等等,这些还是很难直接在 UT 中被测试)

  Java代码


UserDAO:
Collection users = query(UserCriteria criteria);


  你可会这样写 Mock

  Java代码


UserDao userDao = mock(UserDAO.class);
when(userDao.query(new UserCriteria())).thenReturn(users);// users 是你设定好的返回值


  不幸的是,这样写是错的。即便是这样写

  Java代码


when(userDao.query(any(UserCriteria.class))).thenReturn(users);// users 是你设定好的返回值


  这样写虽然可以正常运行,但是这样的测试是不可靠。因为不论 UserCriteria 里的参数是什么,你所 Mock 出来的方法返回的都是你期望的值。这显然是与现实不符的。这是需要 Hamcrest 的 Matcher 登场了

  Java代码


Matcher matcher = new BaseMatcher() {
    @Override
    public boolean matches(Object o) {
        UserCriteria criteria = (UserCriteria) o;
        assert criteria.field1;
        assert criteria.field2;
        assert criteria.field3;
        ....
        return true;
    }
};

when(userDao.query(argThat(matcher))).thenReturn(users);// users
 


  注意,这里的 assert 指的是 JUnit 的 assertEquals 等,或 assertThat (我更推荐)。当然,TestNG 的也是可以。但不要使用 Java 中的 assert 关键字。

  这样,你可以对你 Mock 的方法的入参做细致的检查了。

  测试支持代码

  一个项目的单元测试的代码通常都是直接针对项目主目录中代码的测试,但是一些情况下,你需要针对你所使用的技术开发一些代码以辅助你的单元测试。这些代码既不是你的项目功能实现,也没有测试任何一个方法。一个的框架,尤其是那些非基础设施类的框架(基础设施类的框架如数据库相关的 Hibernate、iBatis 等),往往都提供了方便用户单元测试的辅助代码。例如,Spring Framework 有专门用户测试的子模块 spring-test,Spring MVC 也有帮助测试的类。Apache Camel 也有专门用于简化测试的子项目(Camel Test)。但如果不凑巧,你用的技术直接测试起来不方便,同时有没有相关的简化测试的类库,那不要犹豫了,自己丰衣足食吧。(我在项目中用到的 Sip Servlet 是这么一个非主流的技术)