单元测试

1,589 阅读5分钟

为了降低线上代码的bug率,和项目的运行的覆盖率,作为部门的新同学,为了尽快的熟悉项目,领导安排我补项目的单元测试工作,有一些的自己的心得,有一些的网友的分享。自己结合总结了一下。

首先,好的单元测试必须遵守 AIR 原则,即 Automatic(自动化)、Independent(独立性)、Repeatable(可重复)。

Automatic(自动化)

单元测试应该是全自动执行的,并且非交互式的。测试用例通常是被定期执行的,执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试。单元 测试中不准使用 System.out 来进行人肉验证,必须使用 assert 来验证。

Independent(独立性)

保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护,单元测试用例之间决不能互相调用,也不能依赖执行的先后次序。但是在实际的测试中,存在这种单元之间数据的依赖关系,为了更好的观察数据的变化,我们可以清掉之前test的结果数据,造一组一模一样的测试数据作为准备数据。

Repeatable(可重复)

单元测试是可以重复执行的,不能受到外界环境的影响。因为单元测试通常会被放到持续集成中,每次有代码 check in时单元测试都会被执行。如果单测对外部环境(网络、服务、中间件等)有依赖,容易导致持续集成机制的不可用。为了不受外界环境影响,可以使用mock实现。

单元测试粒度

对于单元测试,要保证测试粒度足够小,有助于精确定位问题。单测粒度至多是类级别,一般是方法级别。只有测试粒度小才能在出错时尽快定位到出错位置。单测不负责检查跨类或者跨系统的交互逻辑,那是集成测试的领域。

单元测试范围

核心业务、核心应用、核心模块的增量代码确保单元测试通过。新增代码及时补充单元测试,如果新增代码影响了原有单元测试,请及时修正。

具体的一些规范

1、单元测试代码必须写在如下工程目录 src/test/java,不允许写在业务代码目录下。

2、单元测试的基本目标:语句覆盖率达到 70%;核心模块的语句覆盖率和分支覆盖率都要达到 100%。

3、在工程规约的应用分层中提到的 DAO 层,Controller层,可重用度高的 Service,都应该进行单元测试。

4、编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。

Border:边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等;
Correct:正确的输入,并得到预期的结果;
Design:与设计文档相结合,来编写单元测试;
Error:强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得到预期的结果;

5、对于数据库相关的查询,更新,删除等操作,不能假设数据库里的数据是存在的, 或者直接操作数据库把数据插入进去,请使用程序插入或者导入数据的方式来准备数据。准备数据也要尽可能的保证独立。

6、和数据库相关的单元测试,可以设定自动回滚机制,不给数据库造成脏数据,或者将数据清除,也可以避免脏数据造成影响。个人认为清数据会更好一点,可以很清晰的知道哪些表数据会对程序运行产生影响。对于清数据的sql配置文件,要么新开辟一个sql文件,要么只增不减。

7、对于不可测的代码建议做必要的重构,使代码变得可测,避免为了达到测试要求而书写不规范测试代码。

8、测试过程中务必对每一个分支都有一个对应的test。

9、如果存在test关联的验证,为保证test的顺序,使用FixMethodOrder指定测试方法的执行顺序。

10、对于已提供的基础配置数据,开发中的项目往往会有数据结构的调整,所以尽量在原配置文件中修改,即对原始数据只增、不减、不改的原则。

11、对于缓存数据的更新,记得一定要还原。

12、测试前务必要将存对程序的执行有影响的表添加到清除数据的名单。

13、我们一定要在理解业务的基础上做test,要明白测试的要点是什么、在什么样的条件下发生的、发起的动作是什么、我们期望有一个什么样的输出。

说了这么多的规范,其实就是为了保证test要达到我们测试的预期,如果因为test做的不规范导致不通过,影响了项目的发布,这就得不偿失了。