TA的每日心情 | 无聊 昨天 09:05 |
---|
签到天数: 1050 天 连续签到: 1 天 [LV.10]测试总司令
|
什么是单元测试?
在计算机编程中,单元测试又称为模块测试,是针对程序模块的最小单位。来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。
说人话就是我们在项目中的每一个业务方法,都是一个小模块,小单元,应该进行正确性检测。
单元测试的目的是什么?
测试的目的是为了验证业务逻辑是否正确,方法的各种形式输入是否能够返回正确的输出。
如何进行单元测试
Java项目中单元测试的框架有很多,本文中将使用Mockito框架来给大家进行演示。 为什么选择Mockito框架SpringBoot默认的Mock框架就是Mockito,只需要依赖spring-boot-starter-test。
之前我相信大家都用过junit来进行单元测试,Mockito也要配合junit来一起使用。那现在为什么不只用junit来进行单测呢? 原因是业务中的依赖问题!当我们执行一个稍微复杂些的业务方法时,会发现它往往会调用很多其他依赖的远程接口来配合才能完成方法的执行,如果使用junit,那么我们就要构造一个完整的依赖出来,当依赖很多时这是非常麻烦的。
Mockito是GitHub上使用最广泛的Mock框架,并与JUnit结合使用。Mockito框架可以创建和配置mock对象.使用Mockito简化了具有外部依赖的类的测试开发。
1. 单元测试规范
我们所有的测试类都应该写在test包中,如下:
针对于每一个测试业务方法我们都应该进行测试。创建的测试类用测试的类名加上后缀Test来命名,如UserServiceTest。
2. Mockito的使用
我们测试的目的是为了验证业务逻辑是否正确,尽可能的避免该业务方法依赖的其他类造成的困扰。而mockito就可以模拟这些调用的过程,自定义返回值。其核心使用了代理机制。
由于mockito的方法都是静态方法,因此我们可以将静态方法全部导入。
- import static org.mockito.Mockito.*;
复制代码 看看导入方法和没有导入方法的区别:
- Mockito.when(...) 导入前,必须通过类名来调用
- when(...) 导入静态方法后可以直接使用
复制代码 首先我们来看核心的三个注解:
在测试类上标注注解:
- @RunWith(MockitoJUnitRunner.class)
复制代码 将要测试的具体实现类作为属性引入进来,并标注注解。
- @InjectMocks
- 比如需要测试UserService,找到它的实现类UserServiceImpl,作为字段引入进来,
- 并标注该注解。
复制代码 在需要依赖到的其他类字段上标注注解。
2.1 制作模拟调用:
我们可以创建两种对象,一种是mock,一种是spy。这两种对象的区别如下:
1.得到的对象同样可以进行“监管”,即验证和打桩。
2.如果不对spy对象的methodA打桩,那么调用spy对象的methodA时,会调用真实方法。
3.如果不对mock对象的methodA打桩,将doNothing,且返回默认值(null,0,false)。
我们用代码来实现一下。
- /**
- * mock出来的数据不打桩测试的话默认所有操作返回null == 打桩之后就返回打桩设置的值
- * spy出来的数据不打桩测试的话将会执行真实的方法 == 打桩之后执行打桩设置的值
- */
- @Test
- public void test1() {
- List<Integer> spylist = spy(ArrayList.class); //创建一个spy对象
- List<Integer> mocklist = mock(ArrayList.class); // 创建一个mock对象
- spylist.add(1);
- mocklist.add(1);
- System.out.println("spylist打桩之前:"+spylist.get(0));
- System.out.println("mocklist打桩之前:"+mocklist.get(0));
- when(spylist.get(0)).thenReturn(100);
- when(mocklist.get(0)).thenReturn(100);
- System.out.println("spylist打桩后测试:"+spylist.get(0));
- System.out.println("mocklist打桩后测试:"+mocklist.get(0));
- System.out.println("doreturn:"+spylist.get(0));
- System.out.println("spy远程调用不打桩测试:"+pushMsgPlanMapper.getById(any()));
- System.out.println("mock对象不打桩测试:"+mocklist.add(1));
- }
复制代码 结果如下:
2.2 打桩
什么是打桩?就是我们通过模拟某个方法的执行流程,自己设置该方法调用后会返回的值。 我们把要测试类依赖的所有其他类通过@mock注解来模拟出来后,就用打桩来模拟执行,这样就不用管测试类所需要的那些依赖了。
流程如下:
- when(执行的方法调用).thenReturn(期望返回结果);
复制代码 打桩后在执行测试类的过程中遇见了这个方法调用,那么就会直接返回我们设置的期望返回结果。可以看一下上面举出来的例子。
when方法后面可以跟上多个thenReturn,每一个thenReturn方法都代表了方法调用的结果。如
- when(执行的方法调用).thenReturn(期望返回结果1).thenReturn(期望返回结果2).thenReturn(期望返回结果3);
复制代码 当该方法被调用多次时,第一次调用将返回结果1,第二次调用返回结果2... 依次类推。
总结
单元测试的目的就是为了检查我们业务的逻辑正确性。mockito框架提供了数据模拟(mock) 和“打桩”的功能,让我们可以自定义方法的返回结果,减少测试类中的其他依赖类给我们造成的影响,非常好用,赶紧用起来吧!
|
|