- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
编写测试的时候,我们必须保证外部依赖行为一致,也需要模拟一些边界条件,所以我们需要使用 Mock 来模拟对象的行为。SpringBoot 提供了 @MockBean 和 @SpyBean 注解,可以方便地将模拟对象与 Spring 测试相结合,简化测试代码的编写 。
@MockBean 是 Spring Boot Test提供的注解,用于在 Spring Boot 测试中创建一个模拟的 Bean 实例,并注入到测试类中的依赖项中。使用 Mock 可以控制被 Mock 对象的行为:自定义返回值、抛出指定异常等,模拟各种可能的情况,提高测试的覆盖率 。
@SpringBootTest
@RunWith(SpringRunner.class)
public class MyServiceTest {
@MockBean
private ExternalDependency externalDependency;
@Autowired
private MyService myService;
@Test
public void testSomeMethod() {
// 定义外部依赖的行为
Mockito.when(externalDependency.someMethod()).thenReturn("Mocked Result");
// 调用被测试类的方法
// 被测方法内部调用了 ExternalDependency 的 someMethod 方法
String result = myService.someMethod();
// 验证外部依赖的方法是否被调用
Mockito.verify(externalDependency).someMethod();
// 断言结果
assertEquals("Mocked Result", result);
}
}
需要注意的是:使用了 @MockBean ,会创建完全模拟的对象,它 完全替代 了被模拟的 Bean,并且所有方法的调用都被模拟。对于未指定行为的方法,返回值如果是基本类型则返回对应基本类型的默认值,如果是引用类型则返回 null 。
@SpyBean 是 Spring Boot Test 提供的另一个注解,与 @MockBean 作用相似,但是它创建的是部分模拟对象,未指定方法行为时,将执行被模拟对象的 真实实现 ,返回实际方法的执行结果 。
常见的情况是:测试依赖外部资源(例如数据库、文件系统等)的方法,我们要在测试中模拟其中一部分方法的行为,同时保留对外部资源的实际访问,那么可以使用 @SpyBean 。
@SpringBootTest
public class MyServiceTest {
@Autowired
private MyService myService;
@SpyBean
private MyRepository myRepository;
@Test
public void testMyService() {
// 使用 doReturn 方法模拟调用 myRepository 的方法,并返回指定的值
Mockito.doReturn(new MyEntity()).when(myRepository).findById(1L);
MyResult result = myService.doSomething(1L);
Assertions.assertEquals("success", result.getMessage());
}
}
这里有一个很重要的点是: @SpyBean 使用 doReturn 而不是 thenReturn ,因为 Spy 对象是基于实例创建的,而 thenReturn 方法会调用实例方法并返回模拟结果,这可能会导致实例状态发生变化,从而影响后续的测试步骤。换而言之如果 Spy 对象使用 doReturn 就像这样: Mockito.when(myRepository.findById(1L)).thenReturn(new MyEntity()); 这段代码我们本意是指定这个 Spy 对象的 findById(1L) 的行为,但是实际上 when 语句中 myRepository.findById(1L) 已经执行了了实际的逻辑,这可能影响整个测试 。
SpringBoot 测试实践 - 2:单元测试与集成测试 中提到了单元测试用到的 @MybatisTest 以及集成测试用到的 @SpringBootTest 。 @SpringBootTest 加载整个 Spring Boot 应用程序的上下文,就像启动了整个 SpringBoot 应用,而 @MybatisTest 只配置了用于测试 MyBatis 的组件,速度就非常快。完整的项目有大量的测试用例,如果每个测试都重新加载 Spring Context 这样就非常耗时,所以要尽量减少 @SpringBootTest 。
一般业务代码都会注入外部依赖,如果只在测试方法上使用 @Test 注解,这样运行测试就会抛出空指针异常,需要在类上使用 @ExtendWith(SpringExtension.class) 将 Spring 的测试支持集成到 JUnit 5 中,这样就可以在测试类中获得 Spring 容器的支持,以便进行依赖注入、加载配置文件、使用 Spring Bean 等。仅加上这个注解是不够的,Spring 容器内依然没有我们需要的依赖,我们还需要使用 @ContextConfiguration() 指定要加载的配置文件、配置类或其他资源 。
如果说 @SpringBootTest 是初始化好所有项目中用到的 Bean 的话,那 @ExtendWith(SpringExtension.class) 就是按需取用,所以必须保证被测的 类 用到的 所有依赖对象 都装配进 Spring 的 IoC 容器里,否则就会抛出这样的异常:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'com.test.ConfigurationRepository#0':
Unsatisfied dependency expressed through field 'configurationRepository';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.test.ConfigurationRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true)}
我们可以通过 @ContextConfiguration() 来指定配置类或者是类 class。对于被测方法没有使用某些依赖也可以直接用 @MockBean 配置一个Mock 对象,保证测试能正常运行 。
@ExtendWith(SpringExtension.class)
// 指定加载的两个类:RestTemplate.class 和 ExecutorConfig.class
// ExecutorConfig.class 一个自定义的配置类,包含线程池配置
@ContextConfiguration(classes = {RestTemplate.class, ExecutorConfig.class})
class UserServiceTest {
// 注入被测对象
@Autowired
private UserService userService;
// 使用 Mock 代替容器加载依赖
@MockBean
private ConfigurationRepository configurationRepository;
// 通过 @ContextConfiguration,确保 Spring Context 中会包含 RestTemplate 的相关配置
@Autowired
private RestTemplate restTemplate;
}
默认情况下,运行测试 ApplicationContext 会被复用,以加快测试的运行速度。但是在某些情况下,比如:多个测试类继承同一个抽象类,这可能会导致测试运行失败。可以在抽象类或每个子类中使用 @DirtiesContext,让 Spring 在测试这些类后重置 ApplicationContext 。
@DirtiesContext 默认的 classMode 参数为 ClassMode.AFTER_CLASS 该模式会在 整个测试类运行完毕后重新加载 Spring 测试上下文。如果希望每次测试方法运行后都重新加载 ApplicationContext 可以使用 @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) 。
@DirtiesContext 也可以用于方法级别,在方法运行前或运行后标记为需要重新加载 ApplicationContext 。
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class CacheIntegrationTest {
@Autowired
private CacheService cacheService;
@Test
@Order(1)
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
public void testCacheEviction() {
// 模拟缓存数据,缓存实际为 HashMap
cacheService.addToCache("key1", "value1");
cacheService.addToCache("key2", "value2");
}
@Test
@Order(2)
public void testCacheLookup() {
// 从缓存中查找数据
// 因为使用了 @DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD) ApplicationContext 重置,故缓存为空
String value1 = cacheService.getFromCache("key1");
String value2 = cacheService.getFromCache("key2");
}
}
为了不影响测试环境的数据,涉及数据层修改的测试,我们可以使用 H2 数据库或者是像上一节: SpringBoot 测试实践 - 2:单元测试与集成测试 这样的,直接使用专门的测试数据库。还有一种方式是用 Docker 启动一个全新的数据库供测试环境使用。而 Testcontainer 的目标就是简化了整个流程:通过代码的方式指定镜像,测试一启动 Testcontainer 将完成初始化工作,自动拉取镜像并创建容器,测试结束后将关闭对应的容器 。
一些 CI 广泛地使用 TestContainer 保证测试环境的一致性。但是如果本地运行, Testcontainer 依赖本地的 Docker Daemon 或是 Testcontainers Cloud 这样的方案。Windows 本地部署 Docker 也会更麻烦一些 。
TestContainer 需要与容器运行时进行交互,第一次要拉取镜像,所以速度上相对慢一些,但是得益于 Docker, TestContainer 几乎可以启动任何服务,无论是数据库、缓存或者是 MQ 等等的,可以保证外部环境的一致性 。
教程可以参考官方的实践:
Testcontainer Java 官方实践 。
Testcontainer SpringBootTest 案例 。
上一节: SpringBoot 测试实践 - 2:单元测试与集成测试 。
Context Management and Caching Pitfalls on Testing with Spring Boot A Quick Guide to @DirtiesContext Modern Best Practices for Testing in Java Testing :: Spring Framework Protect REST APIs with Spring Security Reactive and JWT Spring - Testing 。
最后此篇关于SpringBoot测试实践-3:@MockBean、@SpyBean、提升测试运行速度、Testcontainer的文章就讲到这里了,如果你想了解更多关于SpringBoot测试实践-3:@MockBean、@SpyBean、提升测试运行速度、Testcontainer的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
SpringBoot-Admin 服务监控 简单介绍 Spring Boot Actuator 是 Spring Boot 自带的一个功能模块, 提供了一组已经开箱即用的生产环境下常用
我想查找通过关键字匹配字段 nameEnglish 或 nameChinese 的模型列表。我花了一个多小时谷歌搜索但我做不到。请帮忙。 Springboot Mongo 入门示例 https://s
(请注意:在调查 this issue 时,我更好地发现了我在此处介绍的问题根源) 我对 Hibernate 和 SpringBoot 非常陌生。我的项目涉及一个搜索引擎,其中索引(javafx 客户
我最近有一个 Web 应用程序从 springboot 升级到 springboot 2。当我将其部署到 Tomcat 8 时,它似乎启动了,但没有完全启动。 在 localhost.2019-09-
我是 Spring boot 的新手...我在运行 Controller 时遇到问题, Description: Field todoService in com.springboot.todoCon
我有一个SpringBoot应用程序,它使用以下配置与PostgreSQL通信,通过AWS Beanstrik部署:。在我将AWS Aurora证书更新为rds-ca-ecc384-g1之前,一切都很
实在是不知道标题写什么了 可以在评论区给个建议哈哈哈哈 先用这个作为标题吧 尝试使用 国内给出的 AI 大模型做出一个 可以和 AI 对话的 网站出来 使用 智普AI 只能 在控制
一、介绍 在实际的软件系统开发过程中,由于业务的需求,在代码层面实现数据的脱敏还是远远不够的,往往还需要在数据库层面针对某些关键性的敏感信息,例如:身份证号、银行卡号、手机号、工资等信息进行加密存储
Selenium Selenium是一个用于Web应用程序自动化测试的开源工具套件。它主要用于以下目的: 浏览器自动化:Selenium能够模拟真实用户在不同浏览器(如Chrome、Fire
一、简介 在实际的项目开发过程中,经常需要用到邮件通知功能。例如,通过邮箱注册,邮箱找回密码,邮箱推送报表等等,实际的应用场景非常的多。 早期的时候,为了能实现邮件的自动发送功能,通常会使用 Ja
SpringBoot:基于redis自定义注解实现后端接口防重复提交校验 一、添加依赖 org.springframework.boot spring
SpringBoot:使用Jackson完成全局序列化配置 一、测试准备 com.fasterxml.jackson.core jackson-cor
springboot:整合rocketmq 一、简易消息操作 生产者整合mq 导入依赖 org.springframework.boot
springboot:常用注解 一、spring常用注解 包扫描+组件标注注解 @Component:泛指各种组件 @Controller、@Service、@Repository都可以称为@Comp
我们经常需要在两个系统之间进行一些数据的交互,这时候我们就需要开发数据交互接口。 一般来说,遇到比较多的接口有HTTP接口、WebService接口、FTP文件传输。今天我要来学习一下在SpringB
背景 近期项目上线,甲方要求通过安全检测才能进行验收,故针对扫描结果对系统进行了一系列的安全加固,本文对一些常见的安全问题及防护策略进行介绍,提供对应的解决方案 跨站脚本攻击 XSS常发生于论坛评论等
1.排除 Spring-boot-starter 默认的日志配置 将原本的 spring-boot-starter 改为 org.springframework.boot
springboot:解决跨域问题 一、跨域简介 URL的组成: // 协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址 http://www.baidu.com:8080/ 只要协
一、自定义Starter 的思路: 创建一个Maven工程,创建三个模块 一个模块为demo-app,一个模块为demo-module,一个模块为demo-module-springboot-star
1.pom.xml 4.0.0 org.springframework.boot spring-boot-starter-parent
我是一名优秀的程序员,十分优秀!