我们都知道单元测试,也常常写单元测试,但是对于什么是单元测试却没有仔细思考过,大概觉得创建一个类继承TestCase,然后写一些assert语句算是了吧。当然我也常常遇到有人认为在Java类中写main函数也算是单元测试的。总之,归结到一句话,我们可能觉得写了一段代码对我的代码中的一个方法进行了验证,算是单元测试了。一直到前不久之前,我也算是这大部分人中的一个。由于我之前写SSH比较多,因此我也想当然得认为要测试一个DAO,必须往数据库里面插入一些数据,然后调用DAO,看能否返回正确的结果这是单元测试。

  根据《测试驱动开发的艺术》一书中的定义,在以下情况中一个测试不是单元测试:

  访问了数据

  有网络通讯

  访问了文件系统

  不与其他任何单元测试同时运行

  必须配置好环境后才能运行

  因为以上情况下,会使单元测试的速度降低,在大型的项目中,时常会有上千个甚至上万个单元测试用例,这个时间的消耗是我们承担不起的,特别是要求修改了代码必须使所有的单元测试都通过才能提交代码的情况。以上情况中的测试都应该规划到集成测试的范畴。

  近在工作中遇到需要通过WebService调用远程服务的情况(大家都知道亚马逊是以贯彻SOA著称的公司),在对业务代码进行单元测试的时候遇到了问题,因为自己去搭建一个测试的WebService太麻烦了,而且还得保证数据是固定,很显然,如果每次运行单元测试的时候WebService都返回不同的结果是不行的。

  在这个时候我们需要EasyMock这样的工具来帮我们了。顾名思义,EasyMock可以让我们很Easy地创建Mock对象来模拟外部依赖。在我的工作中,EasyMock使我们不必要真正的通过网络去远程调用事先搭建好的测试WebService。一般我们先创建一个Mock对象,然后record(录制)这个对象的行为,接着将对象设置为replay(回放)状态,之后我们执行需要测试的业务代码并检验代码是否返回正确的结果,后,我们可以verify(验证)整个过程中,Mock对象是否完成了record阶段的设定。看起来非常复杂,下面是一个实例,WebService本身不是重点。

  一般,WebService提供给外界的是通过WSDL定义的接口,通过一些工具可以生成stub class,stub class包括了一个ServiceClientBuilder,一个ServiceClient接口和一些Model,比如下面的ServiceClient接口:

  在客户端代码中,使用下面的方式实现一个业务逻辑:

public interface ServiceClient {
    public List<String> getGroupsByUser(String username);
}

   在客户端代码中,使用下面的方式实现一个业务逻辑:

public class UserDao {
 
 private ServiceClient client;
 
 public boolean validate(String username) {
     List<String> groups = client.getGroupsByUser(username);
     for (String group : groups) {
         if (group.equals("admin")) {
             return true;
         }
     }
 
     return false;
 }
 
 /**
  * Used by Unit Test and other injection work
  * @param client
  */
 public void setClient(ServiceClient client) {
  this.client = client;
 }
}