如何使用 Mockito 模拟由 Spring 应用程序上下文创建的对象以进行单元测试覆盖?
Posted
技术标签:
【中文标题】如何使用 Mockito 模拟由 Spring 应用程序上下文创建的对象以进行单元测试覆盖?【英文标题】:How to mock object created by spring application context using Mockito for Unit Test coverage? 【发布时间】:2021-05-10 12:45:16 【问题描述】:应用场景: TaskScheduler 以定期 cron 间隔触发。每个调度程序作业将创建多个可运行线程。每个线程都会执行 ETL 过程。
public class LoadTask
private static final AuditLogService AUDIT_LOG_SERVICE =
ApplicationContextUtils.getApplicationContext().getBean("auditLogService", AuditLogService.class);
public void perform(ETLDetailsDTO etlDetailsDTO)
// Business logic
AUDIT_LOG_SERVICE.save(AuditLogBuilder.buildSuccessAuditLog())
AuditLogService 是一个 Service 注解的 Spring 托管 bean。
@Component
public class ApplicationContextUtils implements ApplicationContextAware
@Getter
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext appContext)
applicationContext = appContext;
LoadTask 不是 Spring 托管组件,因此我借助 ApplicationContextUtils 来获取 AuditLogService 的 bean。该应用程序运行良好。在编写LoadTask的单元测试用例时,抛出空指针异常。
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LoadTaskTest
@InjectMocks
private LoadTask loadTask;
@Before
public void setUp()
MockitoAnnotations.initMocks(this);
@Test
public void testPerform()
Mockito.when(ApplicationContextUtils.getApplicationContext().getBean("auditLogService", AuditLogService.class)).thenReturn(new AuditLogService());
loadTask.perform(MockObjectHelper.getETLDetailsDTO());
我无法设置 AUDIT_LOG_SERVICE 的模拟对象并成功运行测试用例。如何 mock 或 spy ApplicationContextUtils 使 LoadTask 不会抛出任何错误?
【问题讨论】:
【参考方案1】:@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LoadTaskTest
@InjectMocks
private LoadTask loadTask;
@Mock
private ApplicationContext applicationContext;
@Mock
private AuditLogService auditLogService;
@BeforeEach
public void setUp()
MockitoAnnotations.openMocks(this);
new ApplicationContextUtils().setApplicationContext(applicationContext);
@Test
public void testPerform()
Mockito.when(applicationContext.getBean("auditLogService", AuditLogService.class)).thenReturn(auditLogService);
loadTask.perform(MockObjectHelper.getETLDetailsDTO());
添加 mockito-inline 依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
【讨论】:
以上是关于如何使用 Mockito 模拟由 Spring 应用程序上下文创建的对象以进行单元测试覆盖?的主要内容,如果未能解决你的问题,请参考以下文章
如何模拟 JWT 令牌以将其与 Mockito 和 Spring Boot 一起使用
Mockito 用 Spring 模拟:“传递给 verify() 的参数不是模拟!”
使用 Spring Boot 和 Mockito 模拟对象方法调用
Kotlin,Spring book,Mockito,@InjectMocks,使用与创建的不同的模拟