Mockito @InjectMocks注解完全指南:Java单元测试中的依赖注入模拟
使用Mockito的@InjectMocks注解可以在被注解的类中注入模拟依赖的对象。当我们需要对一个类进行模拟时,如果该类有外部依赖,我们可以使用@Mock或@Spy注解来指定要注入的模拟对象。
Mockito @InjectMocks 注解详解
Mockito尝试使用三种不同的方法注入模拟的依赖项,并按照指定的顺序进行:
- 构造器注入 – 当类定义有构造器时,Mockito会尝试使用最大的构造器来注入依赖项。
- 基于Setter方法 – 当没有定义构造器时,Mockito会尝试使用Setter方法来注入依赖项。
- 基于字段 – 如果无法进行构造器或基于Setter的注入,那么Mockito将尝试直接注入依赖项到字段本身。
如果只有一个匹配的模拟对象,那么Mockito将注入该对象。如果有多个相同类的模拟对象,则使用模拟对象名称来注入依赖项。
@InjectMocks 使用示例
让我们创建一些具有依赖关系的服务和类,以便我们可以看到Mockito依赖注入模拟的实际效果。
服务类
package com.Olivia.injectmocksservices;
// 服务接口
public interface Service {
public boolean send(String msg);
}
package com.Olivia.injectmocksservices;
// 邮件服务实现
public class EmailService implements Service {
@Override
public boolean send(String msg) {
System.out.println("发送邮件");
return true;
}
}
package com.Olivia.injectmocksservices;
// 短信服务实现
public class SMSService implements Service {
@Override
public boolean send(String msg) {
System.out.println("发送短信");
return true;
}
}
具有依赖项的应用程序服务类
package com.Olivia.injectmocksservices;
// 基于构造函数的@InjectMocks注入
public class AppServices {
private EmailService emailService;
private SMSService smsService;
public AppServices(EmailService emailService, SMSService smsService) {
this.emailService = emailService;
this.smsService = smsService;
}
public boolean sendSMS(String msg) {
return smsService.send(msg);
}
public boolean sendEmail(String msg) {
return emailService.send(msg);
}
}
package com.Olivia.injectmocksservices;
// 基于属性Setter方法的@InjectMocks注入
public class AppServices1 {
private EmailService emailService;
private SMSService smsService;
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
public void setSmsService(SMSService smsService) {
this.smsService = smsService;
}
public boolean sendSMS(String msg) {
return smsService.send(msg);
}
public boolean sendEmail(String msg) {
return emailService.send(msg);
}
}
package com.Olivia.injectmocksservices;
// 基于字段的@InjectMocks注入
public class AppServices2 {
private EmailService emailService;
private SMSService smsService;
public boolean sendSMS(String msg) {
return smsService.send(msg);
}
public boolean sendEmail(String msg) {
return emailService.send(msg);
}
}
@InjectMocks 构造函数注入示例
package com.Olivia.mockito.injectmocks;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import com.Olivia.injectmocksservices.AppServices;
import com.Olivia.injectmocksservices.AppServices1;
import com.Olivia.injectmocksservices.AppServices2;
import com.Olivia.injectmocksservices.EmailService;
import com.Olivia.injectmocksservices.SMSService;
class MockitoInjectMocksExamples extends BaseTestCase {
@Mock EmailService emailService;
@Mock SMSService smsService;
@InjectMocks AppServices appServicesConstructorInjectionMock;
@InjectMocks AppServices1 appServicesSetterInjectionMock;
@InjectMocks AppServices2 appServicesFieldInjectionMock;
@Test
void test_constructor_injection_mock() {
when(appServicesConstructorInjectionMock.sendEmail("邮件")).thenReturn(true);
when(appServicesConstructorInjectionMock.sendSMS(anyString())).thenReturn(true);
assertTrue(appServicesConstructorInjectionMock.sendEmail("邮件"));
assertFalse(appServicesConstructorInjectionMock.sendEmail("未模拟的邮件"));
assertTrue(appServicesConstructorInjectionMock.sendSMS("短信"));
}
}
你有没有注意到我的测试类继承了BaseTestCase。这是为了在测试之前初始化Mockito的模拟对象,以下是该类的代码。
package com.Olivia.mockito.injectmocks;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.MockitoAnnotations;
class BaseTestCase {
@BeforeEach
void init_mocks() {
MockitoAnnotations.initMocks(this);
}
}
如果您不调用MockitoAnnotations.initMocks(this);
,那么您将会得到NullPointerException
。另外,我正在使用JUnit 5来运行测试用例。如果您对此不熟悉,请查看JUnit 5教程。
@InjectMocks Setter方法注入示例
@Test
void test_setter_injection_mock() {
when(appServicesSetterInjectionMock.sendEmail("新邮件")).thenReturn(true);
when(appServicesSetterInjectionMock.sendSMS(anyString())).thenReturn(true);
assertTrue(appServicesSetterInjectionMock.sendEmail("新邮件"));
assertFalse(appServicesSetterInjectionMock.sendEmail("未模拟的邮件"));
assertTrue(appServicesSetterInjectionMock.sendSMS("短信"));
}
@InjectMocks 基于字段的注入示例
@Test
void test_field_injection_mock() {
when(appServicesFieldInjectionMock.sendEmail(anyString())).thenReturn(true);
when(appServicesFieldInjectionMock.sendSMS(anyString())).thenReturn(true);
assertTrue(appServicesFieldInjectionMock.sendEmail("邮件"));
assertTrue(appServicesFieldInjectionMock.sendEmail("新邮件"));
assertTrue(appServicesFieldInjectionMock.sendSMS("短信"));
}
您可以从我们的GitHub代码库中查看完整的代码和更多的Mockito示例。
参考:API文档