7

Java-Mock 简化单元测试

 3 years ago
source link: https://xie.infoq.cn/article/eb5352ade963a1671d646b2ac
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

单元测试目的

维基百科对单元测试的定义:

单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。

单元测试的目标是隔离程序部件并证明这些单个部件是正确的。

  • 画外音:单元测试是比较细粒度的测试,是对接口、方法、函数的测试,目的是保障代码按照正确的方式去执行,提高代码质量。

单元测试实施原则

Mock脱离数据库 + 不启动Spring + 优化测试速度 + 不引入项目组件

单元测试不应该依赖数据,依赖外部服务或组件等,会对其他数据产生影响的情况。启动Spring容器,一般比较慢,可能会启动消息监听消费消息,定时任务的执行等,对数据产生影响。

Mock测试就是在测试过程中,对那些当前测试不关心的,不容易构建的对象,用一个虚拟对象来代替测试的情形。

说白了:就是解耦(虚拟化)要测试的目标方法中调用的其它方法,例如:Service的方法调用Mapper类的方法,这时候就要把Mapper类Mock掉(产生一个虚拟对象),这样我们可以自由的控制这个Mapper类中的方法,让它们返回想要的结果、抛出指定异常、验证方法的调用次数等等。

减少单元测试对外部的依赖和副作用,提高单元测试效率

  1. 不使用 @Autowired,@Resource, 需要启动 Spring 容器,测试速度慢,会产生副作用;

  2. 不使用 @SpringBootTest,@SpringBootTest(classes = Application.class), 这会启动整个 SpringBoot 服务

  3. 不应调用数据库,除非是做数据库操作相关的测试,虽然可配置事务回滚,但大多数情况下还是会产生脏数据等问题

  4. 使用Assert断言,用于判断某个特定条件下某个方法的行为,为了证明某段代码的执行结果和期望的一致

  • 画外音:单元测试应小而轻,提交测试效率,较少对外部的依赖,比如数据库、Spring容器、网络服务等,而只关心我们自己的代码,通过Mock来解决对外部的依赖

Mockito的使用

基本使用

  1. 使用静态方法 mock()

  2. 使用注解 @Mock 标注

如果使用@Mock注解, 必须去触发所标注对象的创建. 可以使用 MockitoRule来实现. 它调用了静态方法MockitoAnnotations.initMocks(this) 去初始化这个被注解标注的字段.或者也可以使用@RunWith(MockitoJUnitRunner.class).

“when thenReturn”和”when thenThrow”

模拟对象可以根据传入方法中的参数来返回不同的值, when(….).thenReturn(….)方法是用来根据特定的参数来返回特定的值.

我们也可以使用像 anyString 或者 anyInt anyLong any 这样的方法来定义某个依赖数据类型的方法返回特定的值.

“doReturn when” 和 “doThrow when”

doReturn(…).when(…)的方法调用和when(….).thenReturn(….)类似.对于调用过程中抛出的异常非常有用.而doThrow则也是它的一个变体.

常用注解

@Mock:对函数的调用均执行mock(即虚假函数),不执行真正部分。

@Spy:对函数的调用均执行真正部分。

@InjectMocks:创建一个实例,简单的说是这个Mock可以调用真实代码的方法,使用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。

Mockito中的Mock和Spy都可用于拦截那些尚未实现或不期望被真实调用的对象和方法,并为其设置自定义行为。二者的区别在于Mock不真实调用,Spy会真实调用。

@MockBean: 功能同 @Mock, 只是会将实例放入 Spring 容器管理

@SpyBean: 功能同 @Spy, 只是会将实例放入 Spring 容器管理

  1. Spy 和 Mock 生成的对象不受 Spring 管理

  2. Spy 调用真实方法时,其它 bean 是无法注入的,要使用注入,要使用 SpyBean

  3. SpyBean 和 MockBean 生成的对象受 Spring 管理,相当于自动替换对应类型 bean 的注入,比如 @Autowired、@Resource 等注入

最佳实践

// 不使用 @SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class ExamAnswerComponentTest {

// 创建一个实例,会注入Mock变量
@InjectMocks
private ExamAnswerComponent examAnswerComponent = new ExamAnswerComponentImpl();

// 相关操作会被Mock掉
@Mock
private ExamAnswerCacheObjectiveDAO examAnswerCacheObjectiveDAO;

@Before
public void setUp() {
// 初始化Mock
MockitoAnnotations.initMocks(this);

// given...willReturn 指定方法参数,模拟返回值
given(examAnswerCacheObjectiveDAO.selectByBizIdAndPaperAndQuestion(any(), any(), any()))
.willReturn(new ExamAnswerCacheObjectivePO());
given(examAnswerCacheObjectiveDAO.insert(any())).willReturn(1);
given(examAnswerCacheObjectiveDAO.updateUserAnswerById(any(), any())).willReturn(1);
}


@Test
public void saveOrUpdateAnswerCacheObjective() {

ExamAnswerCacheObjectivePO po = new ExamAnswerCacheObjectivePO();
po.setBizId(100000015L);
po.setBizType(9);
po.setUserAnswer("A");
po.setGroupPaperId(1000320L);
po.setQuestionId(1000042L);
po.setQuestionType(1);

int affect = examAnswerComponent.saveOrUpdateAnswerCacheObjective(po);
System.out.println("affect = " + affect);
Assert.assertTrue(affect > 0);
}

}


参考

https://www.codenong.com/cs106503150/


Recommend

  • 4

    「测试」 - 接口测试 & mock工具Moco 当需要调用第三方HTTP接口时,别人的接口还没完成,可先根据接口定义文档,返回适当的数据,以便开发。在...

  • 8
    • last2win.com 2 years ago
    • Cache

    IDEA-Java自动生成单元测试

    最近在写单元测试,感觉写Mock写烦了,于是想看看有没有现成的spring项目的单元测试生成工具。 网上找到了一个Java单元测试回答的集合:Automatic...

  • 4
    • www.justdojava.com 2 years ago
    • Cache

    Mockito 一个优秀的 Mock 测试框架

    Hello 大家好,我是阿粉,日常工作中很多时候我们都需要同事间的相互配合协作完成某些功能,所以我们经常会遇到服务或者应用内不同模块之间要互相依赖的场景。比如下面的场景,serviceA 中的 methodA() 方式依赖 serviceB

  • 3
    • my.oschina.net 2 years ago
    • Cache

    Java非Spring框架下的单元测试

    当下的大部分的Java项目都是基于Spring框架的,这固然带来了很大的便利,但是也引入了一些其他的问题。例如在对Service、Component进行单元测试的时候,虽然Junit等测试框架提供了相关框架的支持,但是如果是一个有点儿历史的、封装并不是很很合理的、方法类的...

  • 4
    • www.techug.com 2 years ago
    • Cache

    处理 Java 中的不稳定单元测试

    不稳定测试简介 单元测试是持续集成(CI)系统的基石。在软件工程师新实现的代码合并到已有代码之前,它会对其中的错误和已有代码中的回归给出警告。 它提升了软件的可靠性,还提高了开发人员的整体生产力,因为他们在软件开发生命周期的早期就...

  • 5

    6.3 利用Go语言接口进行Mock单元测试 2022-11-23  约 1117 字   预计阅读 3 分钟    次阅读  单元测试重点是对代码逻辑进行测试,也就是证明:为什么你的代码是正确的。Mock测试是单元测试中常用的一种手段,特别是对于...

  • 0

    为什么使用Mock进行单元测试?从功能开发完成的定义来看,至少包括:代码本身、文档及单元测试。而往往在实际开发中,由于需求的不停的变化,导致文档及单元测试是开发过程中直接被忽略的内容。反观优秀的开源项目,在全球...

  • 3

    python3的单元测试模块mock与性能测试模块cProfile首页 - Python/2019-06-14

  • 7

    Golang高效编写单元测试的技巧之Mock codingcn · 大约12小时之前 · 187...

  • 9
    • www.51cto.com 8 months ago
    • Cache

    简化Java单元测试数据

    简化Java单元测试数据 作者:Thoughtworks洞见 2023-07-28 10:27:48 开发 EasyModeling可以帮助 Java 单元测试的编写者快速构造用于测...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK