模拟一个自动装配的 spring 依赖项(接口),它不被测试 class 直接使用
Mock an autowired spring dependency (Interface) which is not directly used by the test class
问题(简而言之)- 我如何模拟一个 spring 在我的 JUnit 中没有直接引用的依赖项。
以下是正在使用的设置。
ServiceA 是一个接口,它的实现需要一些自动装配的依赖项才能使其许多逻辑正常工作。
public interface ServiceA{
void invoke();
...10 more methods
}
@Service
public class ServiceAImpl implements ServiceA{
@Autowired
private ServiceB serviceB;
@Autowired
private ServiceC serviceC;
@Autowired
private DAOA daoA;
@Autowired
private DAOB daoB;
@Override
public void invoke(arg1, arg2){
// use above dependencies to do something
serviceB.sendEmail(args);
}
}
ServiceB 通过调用另一个实用程序依赖项来发送电子邮件。
public interface ServiceB{
void sendEmail();
...10 more methods
}
@Service
public class ServiceBImpl implements ServiceB{
@Autowired
private EmailUtil emailUtil;
@Override
public void sendEmail(args){
emailUtil.sendEmail(args);
}
值得注意的是 sendEmail 方法 returns void.
@Component
publIt'sclass EmailUtil{
@Autowired
private JavaMailSenderImpl javaMailSenderImpl;
public void sendEmail(args){
// send email using spring & other APIs
}
}
我的集成测试 JUnit 如下所示。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
public class ServiceIT{
@Autowired
private ServiceA serviceA;
@Test
public void testA(){
// prepare data mock in H2 DB
serviceA.invoke(arg1, arg2);
// assertions
}
}
问题(长)- 我正在使用 H2 作为模拟数据库,因此我的 DAO 调用可以(需要)起作用。我想模拟其他第 3 方集成,例如在 serviceB 中调用 emailUtil.sendEmail 以便不发送电子邮件。因为在我的 JUnit 中使用 serviceA,我的理解是,我需要创建 EmailUtil 的 @Mock 和 @InjectMocks 到 ServiceB 中,这是 @InjectMocks 到 ServiceA 中。当我这样做时,Mockito 会抛出错误,指出 ServiceB 是一个接口。创建 ServiceA、ServiceB 的模拟对象可能不是一个很好的选择,因为那样我可能不得不 stub/mock 太多行为。我希望在这些 类 中执行实际逻辑,模拟应该只对 sendEmail 方法进行。
- 这是一个常见问题吗?
- 我该如何解决这个问题?
- 这段代码的设计是否有问题(即使用
接口和自动装配一切),这使得很难
test/mock。如果是,什么是更好的方法?
Spring - 4.0.3.RELEASE,JUnit - 4.12,mockito-core - 1.10.19
在测试中 class ServiceIT
mock EmailUtil
using @MockBean
Annotation that can be used to add mocks to a Spring ApplicationContext. Can be used as a class level annotation or on fields in either @Configuration classes, or test classes that are @RunWith the SpringRunner.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
public class ServiceIT{
@Autowired
private ServiceA serviceA;
@MockBean
private EmailUtil emailUtil;
@Test
public void testA(){
// prepare data mock in H2 DB
//given(this.emailUtil.sendEmail(ArgumentMatchers.any()).willReturn( custom object);
serviceA.invoke(arg1, arg2);
// assertions
}
}
问题(简而言之)- 我如何模拟一个 spring 在我的 JUnit 中没有直接引用的依赖项。
以下是正在使用的设置。 ServiceA 是一个接口,它的实现需要一些自动装配的依赖项才能使其许多逻辑正常工作。
public interface ServiceA{
void invoke();
...10 more methods
}
@Service
public class ServiceAImpl implements ServiceA{
@Autowired
private ServiceB serviceB;
@Autowired
private ServiceC serviceC;
@Autowired
private DAOA daoA;
@Autowired
private DAOB daoB;
@Override
public void invoke(arg1, arg2){
// use above dependencies to do something
serviceB.sendEmail(args);
}
}
ServiceB 通过调用另一个实用程序依赖项来发送电子邮件。
public interface ServiceB{
void sendEmail();
...10 more methods
}
@Service
public class ServiceBImpl implements ServiceB{
@Autowired
private EmailUtil emailUtil;
@Override
public void sendEmail(args){
emailUtil.sendEmail(args);
}
值得注意的是 sendEmail 方法 returns void.
@Component
publIt'sclass EmailUtil{
@Autowired
private JavaMailSenderImpl javaMailSenderImpl;
public void sendEmail(args){
// send email using spring & other APIs
}
}
我的集成测试 JUnit 如下所示。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
public class ServiceIT{
@Autowired
private ServiceA serviceA;
@Test
public void testA(){
// prepare data mock in H2 DB
serviceA.invoke(arg1, arg2);
// assertions
}
}
问题(长)- 我正在使用 H2 作为模拟数据库,因此我的 DAO 调用可以(需要)起作用。我想模拟其他第 3 方集成,例如在 serviceB 中调用 emailUtil.sendEmail 以便不发送电子邮件。因为在我的 JUnit 中使用 serviceA,我的理解是,我需要创建 EmailUtil 的 @Mock 和 @InjectMocks 到 ServiceB 中,这是 @InjectMocks 到 ServiceA 中。当我这样做时,Mockito 会抛出错误,指出 ServiceB 是一个接口。创建 ServiceA、ServiceB 的模拟对象可能不是一个很好的选择,因为那样我可能不得不 stub/mock 太多行为。我希望在这些 类 中执行实际逻辑,模拟应该只对 sendEmail 方法进行。
- 这是一个常见问题吗?
- 我该如何解决这个问题?
- 这段代码的设计是否有问题(即使用 接口和自动装配一切),这使得很难 test/mock。如果是,什么是更好的方法?
Spring - 4.0.3.RELEASE,JUnit - 4.12,mockito-core - 1.10.19
在测试中 class ServiceIT
mock EmailUtil
using @MockBean
Annotation that can be used to add mocks to a Spring ApplicationContext. Can be used as a class level annotation or on fields in either @Configuration classes, or test classes that are @RunWith the SpringRunner.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
public class ServiceIT{
@Autowired
private ServiceA serviceA;
@MockBean
private EmailUtil emailUtil;
@Test
public void testA(){
// prepare data mock in H2 DB
//given(this.emailUtil.sendEmail(ArgumentMatchers.any()).willReturn( custom object);
serviceA.invoke(arg1, arg2);
// assertions
}
}