单元自测Java 单元测试规范

目录

1、前言

1.1 定义

1.2 单元测试CheckList

1.3 测试模型

1.3.1 冰淇淋模型

1.3.2 金字塔模型

1.4 为什么要做单元测试

1.5单元测试编码规则

1.6 单元测试用例的设计要素 

2、测试框架介绍

3、单元测试开发规范

3.1 注意事项

3.2 命名规范

3.3 输入数据规范

3.4 结果校验规范


1、前言

1.1 定义

        单元测试(unit testing),是指对软件中的最小可测单元进行检查和验证。单元测试中的单元,可以是C语言中的一个函数,可以是Java语言中的一个类或者方法,图形化软件中的一个窗口或一个菜单。

        总的来说,单元就是一个最小的被测功能模块。(来自百度百科)

        我们做单元测试的目的,就是要验证代码里最小的功能模块,确保它的运行结果是正确的,经得起考验的。就好像一辆汽车,它的每个小零件都需要不断打磨和测试,才能放心的组装在一起,整车质量才能有所保障。

1.2 单元测试CheckList

  • 符合单元测试命名规范
  • 符合单元测试结果断言校验
  • 排除敏感用户数据进行测试
  • 需检查存在的越权风险(数据、端口)
  • 覆盖完整的业务场景(正例、反例)
  • 需可重复执行,结果一致
  • 执行时间短
  • 存在测试价值和方便定位问题
  • 需通过单元测试
  • 需通过要求的代码覆盖率
  • 需不影响项目构建和运行

1.3 测试模型

1.3.1 冰淇淋模型

         传统的冰淇淋模型也是目前很多团队的主要测试手段。这里面包含了大量的手工测试,端到端的自动化测试,以及极少量的单元测试。这种测试方法造成的后果是,随着业务逻辑越来越复杂,手工回归测试的时间越来越长,可以会被漏测的风险越来越大,质量很难把控。自动化测试一旦失败,调用链路中到底是哪里出的问题,需要花费更大的精力去排查。单元测试又少的可怜,基本起不到作用。

1.3.2 金字塔模型

        Mike Cohn 在他的著作《Succeeding with Agile》一书中提出了“测试金字塔”的概念。金字塔模型告诉搭建测试是需要分层的,同时也让大家能够直接的感受到,每一层都需要投入多少测试精力,以及每一层测试的效率和所消耗的成本。

        越是底层的测试,关联性越小,我们只需要关注单个方法的逻辑,简单的单元测试就很容易做到100%的代码覆盖,这也是最快的最节省资源成本的做法。越往上层,多个单元的集成测试涉及到的业务逻辑越复杂,任何一个分支的测试效率会更低,遇到问题更难以排查,所消耗的资源成本,时间成本更大。

        我们的底层越牢,越可靠,上层越不容易出现问题。因此传统的冰淇淋模型要向金字塔模型转化,我们可以形象的称之为“冰淇淋融化了”(让我想起了某酸奶0.0)。也就是说,最顶部的手工回归测试,需要向下融化,优先考虑做全面的单元测试,单元测试覆盖不了的,再进行分层,做服务端的集成测试,集成测试无法覆盖,最后放在UI层。

测试方法类型描述基准
单元测试白盒子测试主要测试单元内部的数据结构、逻辑关系、异常处理逻辑覆盖率
集成测试灰盒子测试主要测试模块间的接口数据传递关系,以及组合功能接口测试
系统测试黑盒子测试主要测试整个系统是否符合业务需求需求覆盖率

        白盒子测试: 又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,即清楚盒子内部的东西以及里面是如何运作的。“白盒”法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。“白盒”法是穷举路径测试。在使用这一方案时,测试者必须检查程序的内部结构,从检查程序的逻辑着手,得出测试数据。贯穿程序的独立路径数是天文数字。

        灰盒测试:是介于白盒测试黑盒测试之间的一种测试,灰盒测试多用于集成测试阶段,不仅关注输出、输入的正确性,同时也关注程序内部的情况。灰盒测试不像白盒那样详细、完整,但又比黑盒测试更关注程序的内部逻辑,常常是通过一些表征性的现象、事件、标志来判断内部的运行状态。

        黑盒测试:它是通过测试来检测每个功能是否都能正常使用。在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确的输出信息。黑盒测试着眼于程序外部结构,不考虑内部逻辑结构,主要针对软件界面和软件功能进行测试。

                                                                                                                 ——来源百度百科    

1.4 为什么要做单元测试

        有效的单元测试是敏捷开发的基石,是软件测试的基础。

        单元测试是每个软件项目不可以或缺的环节,能帮助项目验证代码的主要逻辑,及时发现项目代码变更影响,从而减少SIT、UAT测试上的bug。单元测试覆盖率越少,系统测试阶段暴露bug会越多,解决成本也会越高,代码变更影藏风险越高。

        图

1.5单元测试编码规则

        单元测试应考虑的各种场景下测试条件,应该遵循BCDE原则,以保证模块交付质量。

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

1.6 单元测试用例的设计要素 

        从设计覆盖角度,条件组合>最小线性无关路径>条件>分支>语句。

        将内部逻辑与外部请求分开测试

        对服务边界(interface)的输入和输出进行严格验证

        一定具备断言的能力

        适时使用 setup 和 teardown

        原子性,所有的测试只有两种结果:成功和失败(为什么我每次还多一个,代码报错...)

        避免随机结果

        避免测试中的逻辑,即不包含if、switch、for、while等

        不要保护起来,try……catch……

        每个用例只测试一个关注点

        断言(assertion)是一种在程序中的一阶逻辑(如:一个结果为真或假的逻辑判断式),目的为了表示与验证软件开发者预期的结果——当程序执行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止执行,并给出错误信息。

                                                                                                                 ——来源百度百科

2、测试框架介绍

测试框架类型特点备注
Junit单侧框架+断言主流单元测试框架项目组使用,更轻量,满足大部分需求
Spring Test容器测试支持进行启动Spring容器相关的接口和Service测试,容器只启动一次避免重复加载,支持动态加载Bean,支持数据库测试回滚。非容器相关配置,filter、controller层的测试,则不推荐
Mockitomock提供数据mock和依赖管理,不需要启动容器,即可方便做方法的测试。推荐        
AssertJ断言支持流式处理断言框架,断言丰富项目组使用

        现阶段理解不深,接触的不多,先整理这些,后期如果有更深的认知,再补充!

3、单元测试开发规范

3.1 注意事项

        启动前排除非业务代码的类,如bean、controller、unit、configuration等。

        不推荐使用 spring test 来单元测试,如果有必要用则应该保证单元测试只有一次容器启动,否则会影响项目构建商户时间。

        不建议在构造函数中进行初始化,或者在单元测试方法做一些统一初始化,可以使用 @Before @BeforeClass 进行替代。

        DAO层及远程调用尽量mock掉。

        不建议使用catch进行判断,断言方式有时候并不能达到预期,异常处理案例请参考Demo

        私有方法单测覆盖一般情况可通过反射(powerMockito Whitebox,incokeMethod)进行测试,一般情况下不建议去mock私有方法去验证业务方法,不容易保证业务逻辑正确性。

3.2 命名规范

        一般情况下我们开发的业务系统会有不少的业务层的代码,其中就一个service类的业务方法都有很多个,每个方法都可能返回数种结果。如果我们想要完整的开发单元测试,可能一个service类的单元测试方法会有数十个之多,如果不进行命名规范的管理,会造成命名的混乱,造成的单元测试阅读质量下降,从而影响单元测试维护。

3.3 输入数据规范

        避免使用敏感用户数据来进行测试,避免出现数据泄漏。

        考虑边界数据应该准确有效。

        一个方法的测试数据应该有正例数据和反例数据。

3.4 结果校验规范

        有实际返回,必须要有断言方法来验证结果。

        无返回则可以不考虑使用验证结果,但可以验证内部方法执行次数和抛出异常。

        不允许通过打印日志来确认一些结果(个人不是很理解)。

        涉及特殊格式json/xml等可以断言框架结果验证方式,不可以只做简单结果判断验证

        涉及文件流处理的,建议使用数据类型和大小的结果验证。

        单元测试案例通过

        单元测试结果代码覆盖率达到要求(新增行100%)

测试类命名规范

        比如 UserService 对应测试类  /src/test/java/  所在源 class 同一层级包下;

        比如 com.xxx.UserService 对应的测试类是 com.xxx.UserServiceTest

测试方法命名规范

        推荐使用以下方法命名,方法名应该符合 方法名+条件+结果 对单元测试方法进行命名,需要注意单测函数式 public、无入参和无返回的函数命名。

        <SourceMethodName>对应的源方法名,后面加Test标识是单元测试方法。

        <Condition>名字应该准备描述正例和反例的入参或其他条件。

建议参考以下标识符,如:     

  • 正例条件:RequesetParamisValid
  • 反例条件:NameisBlank(名字为空)、TypeEqualPublic(类型是公共类型)、CardNoisinvalid(卡号无效)、AgeRatherThan(年龄大于30岁)等

而<Behavior>是业务方法期望返回的结果,建议使用以下标识,如:

        ToSuccess(成功)、Tofailed(失败)、ThrowException/ThrowXxException(抛出异常)等。

综上单元测试方法命名样例:

        com.xxx.UserServiceTest.queryUserById

        正例:

         queryUserById_Test_When_RequestParamIsValid_Expect_ToSuccess

        反例:

        queryUserById_Test_When_NameIsBlank_Expect_ToFailed

         queryUserById_Test_When_NotFoundUser_Expect_ToFailed

         queryUserById_Test_When_IdIsNull_Expect_ToFailed

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值