# unit-test-demo **Repository Path**: ck-jesse/unit-test-demo ## Basic Information - **Project Name**: unit-test-demo - **Description**: 基于Junit/TestNG + JMockit 的单元测试demo,以实际案例为基础,以便开发人员应用到实际的自测中。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 1 - **Created**: 2018-12-20 - **Last Updated**: 2024-10-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # unit-test-demo #### 介绍 本demo目前为基于Junit + JMockit 的单元测试demo! 后续待支持:基于TestNG + JMockit 的单元测试demo! 包含但不限于如下案例: > 案例一:Mock类 > > 案例二:Mock实例 > > 案例三:Mock接口 > > 案例四:Mock Spring Bean > > 案例五:Mock MQ消息生产者 > > 案例六:Mock Dubbo消费Bean 子模块 > [unit-test-demo-springboot](https://gitee.com/ckcoy/unit-test-demo/tree/master/unit-test-demo-springboot) 针对springboot下spring/Dubbo/MQ的demo > > [unit-test-demo](https://gitee.com/ckcoy/unit-test-demo/tree/master/unit-test-demo) 针对类、接口、实例的demo # 单元测试简介 ## 什么是单元测试 单元测试是测试应用程序的功能是否能够按需要正常运行。 > 注:通俗一点将就是用来验证某段代码的行为是否与我们期望的一致。 ## 单元测试的目的 保证产品质量。 > 注:通俗一点讲就是减少bug,提高代码质量。 ## 单元测试要写多细 单元测试不是越多越好,而是越有效越好! ## 哪些代码需要有单元测试覆盖 1. 逻辑复杂的 2. 容易出错的 3. 不易理解的,即使是自己过段时间也会遗忘的,看不懂自己的代码,单元测试代码有助于理解代码的功能和需求。 4. 公共代码。比如自定义的拦截器;工具类等。 5. 核心业务代码。一个产品里最核心最有业务价值的代码应该要有较高的单元测试覆盖率。 ## 何时写单元测试 边写业务代码,边写单元测试。因为只有对需求有一定的理解后才能知道什么是代码是正确的。 # 一个实际的开发测试场景 - 场景: > 假设订单服务OrderFacade中有一个下单方法submitOrder(dubbo服务提供者) - 业务逻辑 > 1、调用本地的用户验证类来进行下单前的验证。 > 2、调用多个依赖的dubbo服务来进行业务处理。 - 怎样测试?? > 1、该订单服务(dubbo服务)该怎么进行单元测试? > 2、当用户验证结果不是我想要的结果时,该怎样进行单元测试? > 3、当依赖的dubbo服务未开发完成,或者依赖的dubbo服务的结果不是我想要的结果时,该怎样进行单元测试? - 思路 > 模拟验证结果、模拟dubbo服务(各种模拟)。也就是所谓的Mock。 - 结论 > 上述几个测试场景均可在案例六中找到对应的实现代码。 # JMockit简介 ## JMockit是什么 JMockit是一款Java类/接口/对象的Mock工具,目前广泛应用于Java应用程序的单元测试中。 > JMockit中文网:http://jmockit.cn/ ## JMockit的特点 JMockit的API易用,丰富! JMockit提供了注解,并支持对类/对象的属性,方法,构造函数,初始代码块(含静态初始代码块)进行灵活Mock。(注:支持static,private,public,final,native方法的Mock) 注:JMockit的本质是对java字节码的修改。通俗一点的讲就是在类的某个方法中加入某段逻辑达到Mock的目的。 ## JMockit配置 ```xml org.jmockit jmockit 1.36 test junit junit 4.12 test ``` 注:如果你是通过mvn test来运行你的测试程序 , 请确保JMockit的依赖定义出现在JUnit的依赖之前。 > JMockit提供JUnit4,JUnit5,TestNG的支持。 > 集成的目的是为了让测试程序在运行测试方法前,完成Mock 注解API(@Mocked,@Injectable,@Capturing)修饰的测试属性&测试参数的类做相关字节码的织入。 ## JMockit的程序结构 ![1591695069150](img/1591695069150.png) ![1591695074067](img/1591695074067.png) > 测试属性:即测试类的一个属性。它作用于测试类的所有测试方法。 > 测试参数:即测试方法的参数。它仅作用于当前测试方法。 > Record-Replay-Verification 是JMockit测试程序的主要结构。 > Record: 录制阶段:即录制某类/对象的某个方法调用,在当输入什么时,返回什么。 > Replay: 重放阶段:即重放测试逻辑。 > Verification: 验证阶段:重放后的验证。比如验证某个方法有没有被调用,调用多少次。 > 注:在实际测试程序中,我们更倾向于通过JUnit/TestNG/SpringTest的Assert类对测试结果进行验证。因为对类的某个方法有没调用,调用多少次的测试场景并不多。 ## JMockit注解 ![1591695141740](img/1591695141740.png) ## 案例一:Mock类 - 方式一: 用Expectations来mock类 demo见 ClassMockingByExpectationsTest - 方式二: 用MockUp & @Mock来mock类 demo见 ClassMockingByMockUpTest 注:上面两种方式也是JMockit中支持的两种录制方式。 > ClassMockingByExpectationsTest > ClassMockingByMockUpTest > 本案例中,针对static/private/public/final/native方法 ## 案例二:Mock实例 用Expectations来mock实例(注意:MockUp & @Mock不支持Mock实例) > InstanceMockingByExpectationsTest > 注意:MockUp & @Mock不支持Mock实例 ![1591695214670](img/1591695214670.png) ## 案例三:Mock接口 - 方式一: 用Expectations来mock接口 demo见 InterfaceMockingByExpectationsTest - 方式二: 用MockUp & @Mock来mock接口 demo见 InterfaceMockingByMockUpTest > 注:在Mock接口时,使用@Test和@Injectable注解API,比使用MockUp更方便。因为其可以充分利用JMockit的依赖注入功能。 ## 案例四:Mock Spring Bean - 方式一: 用Expectations来mock demo见 SpringBeanMockingByExpectationsTest - 方式二: 用MockUp & @Mock来mock demo见 SpringBeanMockingByMockUpTest >方式二对接口进行mock时,需要采用MockUp泛型的方式来实现。 >方式二对bean进行mock时,需要mock接口实现类,直接对接口进行mock会不起作用。 >另外,对于Spring Boot程序的Mock,与Mock Spring Bean的方式一致。 >demo见 unit-test-demo-springboot应用 ## 案例五:Mock MQ消息生产者 用MockUp & @Mock来mock ![1591695324005](img/1591695324005.png) ![1591695329117](img/1591695329117.png) ## 案例六:Mock Dubbo消费Bean 方案 1、在spring初始化前,对所有Dubbo消费Bean的进行Mock,即标签里的interface都返回本地默认实现。 2、如果想对某几个Dubbo消费Bean进行Mock,则自定义Dubbo消费Bean的实现即可。 demo见DubboConsumerBeanMockingTest > 注:该demo为一个综合的demo,其中包含有对dubbo消费bean、本地Service、MQ生产者的Mock,以及定制返回结果的Mock。 #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 码云特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)