前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >@Spy、@SpyBean、@MockBean、@Mock、@RunWith、@ExtendWith对比

@Spy、@SpyBean、@MockBean、@Mock、@RunWith、@ExtendWith对比

原创
作者头像
查拉图斯特拉说
发布于 2023-11-09 09:57:02
发布于 2023-11-09 09:57:02
1.3K10
代码可运行
举报
文章被收录于专栏:后端架构后端架构
运行总次数:0
代码可运行

前言

在写单元测试中经常会用到Mockito,但是这些类似的注解非常混乱,今天总结一下相关的注解,说明其中的含义和实现例子。

Mockito.mock() vs @Mock vs @MockBean

Mockito.mock ()方法允许我们创建类或接口的模拟对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void givenCountMethodMocked_WhenCountInvoked_ThenMockedValueReturned() {
    UserRepository localMockRepository = Mockito.mock(UserRepository.class);
    Mockito.when(localMockRepository.count()).thenReturn(111L);

    long userCount = localMockRepository.count();

    Assert.assertEquals(111L, userCount);
    Mockito.verify(localMockRepository).count();
}

@Mock该注释是Mockito.mock()方法的简写。需要注意的是,我们应该只在测试类中使用它。与mock()方法不同的是,我们需要启用Mockito注解才能使用该注解。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RunWith(MockitoJUnitRunner.class)
public class MockAnnotationUnitTest {
    
    @Mock
    UserRepository mockRepository;
    
    @Test
    public void givenCountMethodMocked_WhenCountInvoked_ThenMockValueReturned() {
        Mockito.when(mockRepository.count()).thenReturn(123L);

        long userCount = mockRepository.count();

        Assert.assertEquals(123L, userCount);
        Mockito.verify(mockRepository).count();
    }
}

@MockBean将模拟对象添加到 Spring 应用程序上下文中。模拟将替换应用程序上下文中相同类型的任何现有 bean。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RunWith(SpringRunner.class)
public class MockBeanAnnotationIntegrationTest {
    
    @MockBean
    UserRepository mockRepository;
    
    @Autowired
    ApplicationContext context;
    
    @Test
    public void givenCountMethodMocked_WhenCountInvoked_ThenMockValueReturned() {
        Mockito.when(mockRepository.count()).thenReturn(123L);

        UserRepository userRepoFromContext = context.getBean(UserRepository.class);
        long userCount = userRepoFromContext.count();

        Assert.assertEquals(123L, userCount);
        Mockito.verify(mockRepository).count();
    }
}

JUnit5 @RunWith annotation with the new @ExtendWith

在 JUnit 5 中,@RunWith注释已被更强大的@ExtendWith注释取代。

@RunWith

@RunWith注释在任何较旧的 JUnit 环境中运行 JUnit 5 测试。

JUnitPlatform类是一个基于 JUnit 4 的运行器,允许我们在 JUnit 平台上运行 JUnit 4 测试。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RunWith(JUnitPlatform.class)
public class GreetingsUnitTest {
    // ...
}

基于 JUnit 4 的运行器的测试迁移到 JUnit 5。我们将使用 Spring 测试作为示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SpringTestConfiguration.class })
public class GreetingsSpringUnitTest {
    // ...
}

@ExtendWith

测试迁移到 JUnit 5,我们需要用新的@ExtendWith替换@RunWith注释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { SpringTestConfiguration.class })
public class GreetingsSpringUnitTest {
    // ...
}

@Spy 和 @SpyBean 之间的区别

@Spy注释是 Mockito 测试框架的一部分,它创建真实对象的间谍(部分模拟),通常用于单元测试。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Spy
OrderRepository orderRepository;
@Spy
NotificationService notificationService;
@InjectMocks
OrderService orderService;

@Test
void givenNotificationServiceIsUsingSpy_whenOrderServiceIsCalled_thenNotificationServiceSpyShouldBeInvoked() {
    UUID orderId = UUID.randomUUID();
    Order orderInput = new Order(orderId, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
    doReturn(orderInput).when(orderRepository)
        .save(any());
    doReturn(true).when(notificationService)
        .raiseAlert(any(Order.class));
    Order order = orderService.save(orderInput);
    Assertions.assertNotNull(order);
    Assertions.assertEquals(orderId, order.getId());
    verify(notificationService).notify(any(Order.class));
}

Spring Boot 的@SpyBean注解

@SpyBean注解是Spring Boot特有的,用于与Spring的依赖注入进行集成测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Autowired
OrderRepository orderRepository;
@SpyBean
NotificationService notificationService;
@SpyBean
OrderService orderService;

@Test
void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() {

    Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
    doReturn(true).when(notificationService)
        .raiseAlert(any(Order.class));
    Order order = orderService.save(orderInput);
    Assertions.assertNotNull(order);
    Assertions.assertNotNull(order.getId());
    verify(notificationService).notify(any(Order.class));
}

@Spy@SpyBean之间的区别

在单元测试中,我们使用@Spy,而在集成测试中,我们使用@SpyBean

如果@Spy注解的组件包含其他依赖项,我们可以在初始化时声明它们。如果在初始化期间未提供它们,系统将使用零参数构造函数(如果可用)。在@SpyBean测试的情况下,我们必须使用@Autowired注释来注入依赖组件。否则,在运行时,Spring Boot 会创建一个新实例。

如果我们在单元测试示例中使用 @SpyBean ,则 当 调用NotificationService时,测试将失败并出现NullPointerException因为OrderService需要模拟/间谍 NotificationService

同样,如果在集成测试的示例中使用@Spy ,则测试将失败并显示错误消息“Wanted but not invoked: notificationService.notify(<any com.baeldung.spytest.Order> )”,因为 Spring 应用程序context 不知道 @Spy注解的类相反,它创建一个新的NotificationService实例并将其注入到OrderService 中。

@SpyBean需要手动注入bean,但是@Spy 不需要,除非你调用了依赖

总结

@Spy、@SpyBean、@MockBean、@Mock、@RunWith、@ExtendWith,带bean的就跟集成测试有关,例如集成Spring,如果只是简单的单元测试可以配置不带Bean的,这里面最好区分的还是@RunWith和@ExtendWith,一个是JUnit4一个是JUnit5。

引用

https://www.baeldung.com/java-spring-mockito-mock-mockbean

https://www.baeldung.com/junit-5-runwith

https://www.baeldung.com/spring-spy-vs-spybean

点赞关注评论一键三连,欢迎关注公众号【i查拉图斯特拉如是说】每周分享技术干货、开源项目、实战经验、国外优质文章翻译等,您的关注将是我的更新动力!

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
1 条评论
热度
最新
谢谢分享~
谢谢分享~
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
Springboot+Junit5微服务单元测试编写实践
现在写单元测试的重要性不言而喻,下边说明一下Junit5测试的会用到的主要注解和方法。PS:常用开发工具都可以自动生成Junit测试类。
玖柒的小窝
2021/12/09
1.7K0
Difference between @Mock, @InjectMocks and @Captor
我们的第一个选择是使用MockitoJUnitRunner注释 JUnit 测试:
查拉图斯特拉说
2023/11/09
5941
Difference between @Mock, @InjectMocks and @Captor
Difference between @Mock, @InjectMocks and @Captor
我们的第一个选择是使用MockitoJUnitRunner注释 JUnit 测试:
查拉图斯特拉说
2023/12/19
2730
用过举手!SpringBoot 单元测试利器-Mockito
Mockito 是一种 Java mock 框架,他主要是用来做 mock 测试的,他可以模拟任何 Spring 管理的 bean、模拟方法的返回值、模拟抛出异常...等,在了解 Mockito 的具体用法之前,得先了解什麽是 mock 测试
JAVA葵花宝典
2020/03/11
5K0
一文搞懂Spring5 Mock测试
很多时候我们开发人员测试接口时习惯使用postman去直接测,但是使用postman测试有个缺点就是只适合开发人员自己测试,不太方便团队共享,而且测试的时候很难覆盖到一个接口涉及到各个层面的逻辑分支方法。说到对代码逻辑的覆盖,这方面junit测试就有天然的优势。一般规范一点IT互联网公司都会要求提交的代码都要有测试用例,而且对测试用例的逻辑覆盖率有一定的要求,一般要求覆盖率70%以上。
用户3587585
2022/03/04
3K0
一文搞懂Spring5 Mock测试
如何写好单元测试:Mock脱离数据库+不使用@SpringBootTest「建议收藏」
4、最佳的单元测试写法:Mock脱离数据库+不启动Spring+优化测试速度+不引入项目组件
全栈程序员站长
2022/08/14
3.6K0
如何写好单元测试:Mock脱离数据库+不使用@SpringBootTest「建议收藏」
SpringBoot对单元测试支持、常用单元测试功能使用实例
Spring Boot 提供了许多注解和工具帮助开发人员测试应用,在其官方文档中也用了大量篇幅介绍单元测试的使用。在谷歌每周的 TGIF (ThanksGod, it's Friday)员工大会中有一项就是 宣布-周单元测试竞赛获胜的工程师。谷歌之所以这么重视单元测试,就是为了保证程序质量,鼓励大家多写测试代码。国内大多数开发人员对单元测试有所忽视,这也是我写本章内容的原因所在。
愿天堂没有BUG
2022/10/28
1.9K0
SpringBoot对单元测试支持、常用单元测试功能使用实例
小白搞 Spring Boot单元测试
单元测试的目的: 测试当前所写的代码是否是正确的, 例如输入一组数据, 会输出期望的数据; 输入错误数据, 会产生错误异常等. 在单元测试中, 我们需要保证被测系统是独立的(SUT 没有任何的 DOC), 即当被测系统通过测试时, 那么它在任何环境下都是能够正常工作的. 编写单元测试时, 仅仅需要关注单个类就可以了. 而不需要关注例如数据库服务, Web 服务等组件。
田维常
2021/09/27
4.8K0
SpringBoot - 单元测试利器Mockito入门
Mock 测试就是在测试过程中,创建一个假的对象,避免你为了测试一个方法,却要自行构建整个 Bean 的依赖链。
小小工匠
2021/08/17
17.7K1
SpringBoot - 单元测试利器Mockito入门
JAVA实战:如何让单元测试覆盖率达到80%甚至以上
单元测试(unit testing)是指对软件中的最小可测试单元进行检查和验证。它是软件测试中的一种基本方法,也是软件开发过程中的一个重要步骤。
你可以叫我老白
2023/03/21
4.2K1
JAVA实战:如何让单元测试覆盖率达到80%甚至以上
单元测试
  每个开发人员都写过很多代码、函数,但是你能保证你写的每个函数都能执行并且正常吗?   我们太多时间站在功能需求的角度来审视我们的代码,认为需求实现功能逻辑正常,我们就完成了自己的使命。功能逻辑固然重要这个也是我们的目标。但是仅此而已吗,首先作为开发人员要知道,代码的终极目标有两个:实现需求保证逻辑正常、保证代码质量和可维护性。测试人员只能帮助我们查漏需求是否完整实现,对于代码质量和可维护性是需开发自己保证的,所以单元测试必不可少。
OPice
2019/11/11
1.8K0
手把手教你实战TDD
Tech 导读 本文将对测试驱动开发(TDD)进行探讨,主要阐述了TDD基本概念理解、TDD常见误区、TDD技术选型等,并提供了贫血模型三层架构和DDD下的TDD实战案例。
京东技术
2023/08/22
4860
手把手教你实战TDD
单元测试 - MockBean
使用@MockBean替换Spring上下文中的Bean(这样会导致Spring上下文重启)
十毛
2021/01/20
1.9K0
让你快速上手,从JUnit 4过渡到JUnit 5
在本教程中,我们将介绍如何创建基本的Spring Boot应用程序并将其从JUnit 4迁移到JUnit 5。
用户6543014
2020/03/17
2.8K0
两个基于spring的单元测试简单样例
单元测试,从一定程度上可以看出一个同学达到的层次。但又不完全是,有时可能只是一个思考方式的转变。单元测试有非常多的工具供选择,在java中,junit无疑是比较常用的。本文列出,junit在spring中的使用样例,供参考。
烂猪皮
2021/04/02
8860
使用强大的 Mockito 来测试你的代码
这篇教程介绍了如何使用 Mockito 框架来给软件写测试用例。 1、预备知识 如果需要往下学习,你需要先理解 Junit 框架中的单元测试。 如果你不熟悉 JUnit,请查看下面的教程: http://www.vogella.com/tutorials/JUnit/article.html 2、使用mock对象来进行测试 2.1 单元测试的目标和挑战 单元测试的思路是在不涉及依赖关系的情况下测试代码(隔离性),所以测试代码与其他类或者系统的关系应该尽量被消除。一个可行的消除方法是替换掉依赖类(测试替换),
用户1332428
2018/03/09
11.5K0
使用强大的 Mockito 来测试你的代码
使用 Junit + Mockito 实践单元测试
相信做过开发的同学,都多多少少写过下面的代码,很长一段时间我一直以为这就是单元测试...
JMCui
2020/05/06
5K0
Spring Boot - 用JUnit 5构建完美的Spring Boot测试套件
Spring Boot - Junit4 / Junit5 / Spring Boot / IDEA 关系梳理
小小工匠
2023/09/12
6.7K0
Spring Boot - 用JUnit 5构建完美的Spring Boot测试套件
Mockito模拟进行单元测试
    MOCK意思是模拟的意思,主要被用来进行数据的人工组织,不会真正地调用第三方服务器,类似redis,mysql等都不会调用,也不用关心数据底层是如何进行处理的,我们要做的只是将本单元的逻辑进行单元测试,验证数据的逻辑处理性,而其中mock较好的框架就是Mockito。
chinotan
2019/07/15
9.8K0
Mockito模拟进行单元测试
Spring Boot单元测试用例
单元测试是开发人员为确保单个单元或组件功能正常工作而进行的测试之一。在本教程中,将了解和学习如何使用Mockito和Webrmrp编写单元测试用例。
黑洞代码
2021/11/25
1K0
Spring Boot单元测试用例
相关推荐
Springboot+Junit5微服务单元测试编写实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档