Spring 集成 Java DSL 单元测试 - 如何模拟服务激活器 class 或其他 components/endpoints?
Spring Integration Java DSL unit test - How to mock a Service Activator class or other components/endpoints?
我有一个 class,其中包含如下几个服务激活器方法:
@MessageEndpoint
public class TestService {
@ServiceActivator
public void setComplete(Message<String> message){
//do stuff
}
}
在集成流程中,其中一个渠道调用了以下方法之一:
@Bean
public TestService testService() {
return new TestService();
}
@Bean
public IntegrationFlow testFlow() {
return IntegrationFlows.from("testChannel")
.handle("testService", "setComplete")
.handle(logger())
.get();
}
我正在为此流程编写单元测试并使用 Mockito 来 mcoking 服务激活器 class:
@ContextConfiguration(classes = IntegrationConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class AppTest {
@Mock
private TheGateway startGateway;
@Mock
private TestService testrvice;
@Autowired
@Qualifier("testChannel")
DirectChannel testChannel;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test()
public void testMessageProducerFlow() throws Exception {
Mockito.doNothing().when(startGateway).execute("test");
startGateway.execute("test");
Mockito.verify(startGateway).execute("test");
TestChannel.send(new GenericMessage<>("test"));
Mockito.verify(testService).setComplete(new GenericMessage<>("test"));
}
}
当我不模拟 TestService 时,它会毫无问题地执行流程。
任何关于如何模拟服务激活器 class 的指导都会有所帮助。
更新:
当我模拟它时(如上面的代码片段所示),它不会调用模拟对象,而是执行实际的东西,最后一行 Mockito.verify(testService)...
断言从未调用模拟 testService。
首先你误解了Spring测试框架的工作原理。
@ContextConfiguration(classes = IntegrationConfig.class)
按原样加载配置,不做任何修改,并根据该配置启动应用程序上下文。
根据第一个条件,您的 .handle("testService", "setComplete")
使用 testService()
@Bean
而不是 @Mock
只有在测试 applicationContext 启动后,所有这些 @Mock
s 和 @Autowired
s 才开始工作。
换句话说,您的模拟不会改变原始 IntegrationConfig
中的任何内容。
在框架中使用反射来检索特定 bean 的某些字段以将其替换为模拟。但这并不容易。
我建议您区分集成和服务配置,并使用两种不同的 classes 进行生产和测试。像这样:
必须将 testService()
@Bean
从 IntegrationConfig
移动到新的 @Configuration
class 以进行生产。
TestServiceConfig
可能如下所示:
@Bean
public TestService testService() {
return Mockito.mock(new TestService());
}
最后你的AppTest
应该修改成这样:
@ContextConfiguration(classes = {IntegrationConfig.class, TestServiceConfig.class})
....
@Autowired
private TestService testrvice;
这一切只是因为应用程序上下文和单元测试范围处于不同级别。
我有一个 class,其中包含如下几个服务激活器方法:
@MessageEndpoint
public class TestService {
@ServiceActivator
public void setComplete(Message<String> message){
//do stuff
}
}
在集成流程中,其中一个渠道调用了以下方法之一:
@Bean
public TestService testService() {
return new TestService();
}
@Bean
public IntegrationFlow testFlow() {
return IntegrationFlows.from("testChannel")
.handle("testService", "setComplete")
.handle(logger())
.get();
}
我正在为此流程编写单元测试并使用 Mockito 来 mcoking 服务激活器 class:
@ContextConfiguration(classes = IntegrationConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class AppTest {
@Mock
private TheGateway startGateway;
@Mock
private TestService testrvice;
@Autowired
@Qualifier("testChannel")
DirectChannel testChannel;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test()
public void testMessageProducerFlow() throws Exception {
Mockito.doNothing().when(startGateway).execute("test");
startGateway.execute("test");
Mockito.verify(startGateway).execute("test");
TestChannel.send(new GenericMessage<>("test"));
Mockito.verify(testService).setComplete(new GenericMessage<>("test"));
}
}
当我不模拟 TestService 时,它会毫无问题地执行流程。 任何关于如何模拟服务激活器 class 的指导都会有所帮助。
更新:
当我模拟它时(如上面的代码片段所示),它不会调用模拟对象,而是执行实际的东西,最后一行 Mockito.verify(testService)...
断言从未调用模拟 testService。
首先你误解了Spring测试框架的工作原理。
@ContextConfiguration(classes = IntegrationConfig.class)
按原样加载配置,不做任何修改,并根据该配置启动应用程序上下文。根据第一个条件,您的
.handle("testService", "setComplete")
使用testService()
@Bean
而不是@Mock
只有在测试 applicationContext 启动后,所有这些
@Mock
s 和@Autowired
s 才开始工作。
换句话说,您的模拟不会改变原始 IntegrationConfig
中的任何内容。
在框架中使用反射来检索特定 bean 的某些字段以将其替换为模拟。但这并不容易。
我建议您区分集成和服务配置,并使用两种不同的 classes 进行生产和测试。像这样:
必须将
testService()
@Bean
从IntegrationConfig
移动到新的@Configuration
class 以进行生产。TestServiceConfig
可能如下所示:@Bean public TestService testService() { return Mockito.mock(new TestService()); }
最后你的
AppTest
应该修改成这样:@ContextConfiguration(classes = {IntegrationConfig.class, TestServiceConfig.class}) .... @Autowired private TestService testrvice;
这一切只是因为应用程序上下文和单元测试范围处于不同级别。