简化Java单元测试数据( 三 )


受到 Builder 模式和 Object Mother 思想的启发,我开发了 EasyModeling 来尝试简化 Java 单元测试的编写,并提高测试的可读性和易维护性 。EasyModeling 是一个 Java 注解处理器库,它主要提供三个方面的功能:

  • EasyModeling在编译期根据指定的数据模型类的结构,生成对应的数据模型工厂类,以方便单元测试快速生成数据模型类的实例 。通过向 EasyModeling 注册一个数据模型类,单元测试的编写者只需要调用 EasyModeling 所提供工厂类的静态方法,就可以立即得到这个数据模型类的实例 。
  • EasyModeling 还可以在单元测试的运行时,自动初始化它所生成的数据模型实例 。在生成数据模型实例时,EasyModeling 默认的行为是给数据模型实例的字段填充随机值,让开发者不需要再耗费精力去填充对测试场景无意义的属性 。同时,开发者仍然有机会向 EasyModeling 指定每个数据模型类的每个字段所需的初始化方式 。
  • 另外,EasyModeling 还在其生成的工厂类中提供了一个 Builder 模式的构建器 。利用这个构建器,开发者可以定制、并仅定制与当前测试场景相关的字段,使单元测试简短、清晰、易读 。
在编码层面,EasyModeling 的行为完全发生在测试包中,丝毫不会侵入项目的生产实现代码 。同时,EasyModeling 只会照顾开发者向它注册的数据类型类,而不会在代码库中主动搜索 。所以即使是维护已久的代码库,从任何时间点引入 EasyModeling 都不会造成额外的负担 。
EasyModeling简化后的单元测试 
在引入了 EasyModeling 后,本文中第一节中的单元测试例子可以得到显著地简化:
简化Java单元测试数据

文章插图
图片
除此之外,如前文提到,开发者需要在测试代码中向 EasyModeling 注册 Employee 类:
简化Java单元测试数据

文章插图
图片
【简化Java单元测试数据】首先我们看到,在引入 EasyModeling 后,单元测试的代码在篇幅上得到了非常明显地简化 。在单元测试中 (4) 处,EmployeeModeler 类就是由 EasyModeling 在编译期生成的工厂类,通过引用 EmployeeModeler 类中的静态方法 builder(),我们可以得到 Employee 类的Builder 的实例 。请注意,此处使用的 Builder 类不是由 Employee 类自己编写的,也不是通过如 Lombok 这样的工具来提供的,而是由 EasyModeling 在其生成的工厂类 EmployeeModeler 来提供的 。这样的好处是,为了测试而准备的 Builder 完全没有侵入生产代码 。
其次,在 (4) 处生成的 Builder 类的实例中,EasyModeling 已经为我们尽可能多地填充了所有的成员变量 。因此,我们接下来只需要聚焦在当前测试场景所关心的成员变量上 。例如在 (5) 处,我们将 dateOfJoining 字段的内容设置为指定的日期 。在可读性方面,由于避免了冗长的初始化参数,所以使开发者在阅读单元测试时,能够快速理解测试场景,进而也比较容易修改或维护单元测试 。
第三,EasyModeling 在填充数据模型实例的属性时,不仅能够填充一些 Java 应用中常用的数据类型,包括基本类型、数组、集合、时间日期等等,还能够进一步填充当前数据模型所引用的其他数据模型 。例如 Employee 类中引用的 List<Department> departments 列表字段 。
最后,为了让 EasyModeling 帮我们生成 Employee 类的工厂类,如以上代码中 (6) 处,开发者只需要在任意的一个类上通过 @Model 注解声明即可 。EasyModeling在编译期为所有被 @Model 注解声明的数据模型类生成对应的工厂(Modeler)类 。
除此之外,EasyModeling 还提供了其他一些好用的特性,限于篇幅,具体的用法请参考文档 。
EasyModeling的不足和未来 
但是由于我的业余精力和能力都非常有限,EasyModeling 目前还处于它成长的初期,存在几点显然的不足 。
第一,没有维护良好的使用文档 。目前我只维护了一份项目 Readme 文件,作为简要的使用文档,导致一些略高级的使用方法和一些从新版本开始支持的功能并没有体现在文档中 。
第二,没有维护文档注释 。遵循代码整洁的原则,在长期从事的企业应用开发中,我几乎不会写任何形式的注释 。所以我也没有意识到,在维护一个更偏底层的开源工具库时,充分的文档注释是非常必要的 。一方面,文档注释便于开发者用户查看阅读,也便于有兴趣的贡献者参与开发 。另一方面,由于这种较为基层的工具中无可避免地要使用一些魔法,如果没有良好的注释,随着时间推移,可能连我自己也会忘记其中的细节 。


推荐阅读