我正在使用 Mockito 来模拟 spring beans。
当我模拟接口时它工作得很好。
在我们的应用程序中,很少有@Component bean 没有实现任何接口。
当我尝试模拟此类组件时,spring 上下文尝试将属性注入这些组件内。
Mockito不支持模拟没有实现任何接口的spring组件吗?
按要求附上示例
public interface EmployeeInterface {
public Long saveEmployee(Employee employee);
}
@Component
public class EmployeeImpl implements EmployeeInterface {
@Autowired
public EmailSender emailSender
public Long saveEmployee(Employee employee) {
...
}
}
public interface EmailSender {
public boolean sendEmail(Email email);
}
@Component
public class EmailSenderImpl implements EmailSender {
@Autowired
MailServerInfo MailServerInfo;
public boolean sendEmail(Email email) {
...
}
}
public interface MailServerInfo {
public String getMailServerDetails();
}
@Component
public class MailServerInfoImpl {
public String getMailServerDetails() {
...
}
}
@Profile("Security-test")
@Configuration
public class SecurityTestMockConfiguration {
@Bean
@Primary
public EmailSender emailSender() {
return Mockito.mock(EmailSender.class);
}
}
@ActiveProfiles("Security-test")
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:context-test.xml" })
public class MyTest {
@Autowired
EmployeeInterface employeeInterface;
@Test
public void testSaveEmployee() {
employeeInterface.saveEmployee(employee);
}
}
在上面的示例中,如果我使用 Mockito 模拟 EmailSender,它工作得很好。
在下面的场景中,EmailSender 是一个 Spring 组件,没有实现任何接口。在下面的情况下,我在自动接线期间遇到错误。
public interface EmployeeInterface {
public Long saveEmployee(Employee employee);
}
@Component
public class EmployeeImpl implements EmployeeInterface {
@Autowired
public EmailSender emailSender
public Long saveEmployee(Employee employee) {
...
}
}
@Component
public class EmailSender {
@Autowired
MailServerInfo MailServerInfo;
public boolean sendEmail(Email email) {
...
}
}
public interface MailServerInfo {
public String getMailServerDetails();
}
@Component
public class MailServerInfoImpl {
public String getMailServerDetails() {
...
}
}
@Profile("Security-test")
@Configuration
public class SecurityTestMockConfiguration {
@Bean
@Primary
public EmailSender emailSender() {
return Mockito.mock(EmailSender.class);
}
}
@ActiveProfiles("Security-test")
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:context-test.xml" })
public class MyTest {
@Autowired
EmployeeInterface employeeInterface;
@Test
public void testSaveEmployee() {
employeeInterface.saveEmployee(employee);
}
}
在第二种情况下,自动装配失败,因为 EmailSender 找不到 MailServerInfo 实现。
问题
您经常混合使用框架和注释。 Spring 使用
@Autowired
。 Mockito 使用 @Mock
和 @InjectMocks
。您还可以使用多种方法在测试中配置应用程序上下文 - @Configuration
和 @ContextConfiguration(locations = { ... })
- 但这种方式不起作用。有关所有详细信息,请参阅混合 XML、Groovy 脚本和带注释的类。
问题是您是否想使用模拟编写单元测试,或者是否想不使用模拟而是使用 Spring 上下文编写集成测试?
单元测试
如果你想模拟
EmailSender
那么使用 Mockito 的 @Mock
注释。然后你可以让 Mockito 通过 EmployeeImpl
注入 @InjectMocks
的依赖项。
@Mock
EmailSender emailSender;
@InjectMocks
EmployeeImpl employee;
您还可以看看这样的教程https://dzone.com/articles/use-mockito-mock-autowired
集成测试
如果您想编写集成测试,请使用其中之一
@Configuration
public class TestConfiguration { ... }
@ContextConfiguration(classes = { TestConfiguration.class })
public class MyTest { ... }
或
@ContextConfiguration(locations = { "classpath:context-test.xml" })
public class MyTest { ... }
public EmailSender emailSender;
public EmployeeImpl employeeImpl;
@BeforeEach
public void setUp() {
emailSender= Mockito.mock(emailSender.class);
// Manually create an instance and set mocks
employeeImpl= new EmployeeImpl (emailSender);
}