Testing Spring Integration Gateways
0 CommentsSpring Integration Gateways are one of my favorite features of Spring Integration. As a developer, you write an interface for the Spring Integration Gateway, and at runtime Spring Integration will provide you an implementation of the class via the Spring Context for your application to use.
What is nice about this approach, the complexities of the messaging layer is completely hidden from your application code. There is no ‘leakage’ of the messaging layer into your application layer. From the standpoint of the developer, you are simply making a method call on a class which implements the interface you wrote for your Spring Integration Gateway.
Spring Integration Gateway Example
Overview
For our example today, lets say you’re working on a large ecommerce website. You need to call a service to retrieve product data. Spring Integration is a natural choice to handle this type of request. For integration with the service on the website, you’ve decided to use a Spring Integration Gateway. This way the message based request to the backend service is completely abstracted from your existing code.
Model
For our example, we want to return a product. In a large ecommerce web site, your Product class would be much more complex. However, this simple POJO is fine for demonstrating the capabilities of Spring Integration.
package guru.springframework.si.model; public class Product { private String productId; private String description; public String getProductId() { return productId; } public void setProductId(String productId) { this.productId = productId; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
Spring Integration Gateway
Here is the code for our Spring Integration Gateway. This is the interface you will use in your application.
package guru.springframework.si.gateways; import guru.springframework.si.model.Product; import org.springframework.integration.annotation.Gateway; public interface ProductGateway { @Gateway(requestChannel = "getProductChannel") Product getProduct(String productId); }
Product Service
The Product Service could be a number of things in a real enterprise application. Might be a web service, could be a JMS or AQMP queue, a Spring Data Repository, or even a traditional DAO. For this demonstration, keep in mind this would be some type of different service you’d call to retrieve product data. I’ve created a very simple stub of a service class that just returns a Product
object.
package guru.springframework.si.testservice; import guru.springframework.si.model.Product; import org.springframework.stereotype.Service; @Service public class ProductService { public Product getProduct(String productId) { Product product = new Product(); product.setProductId(productId); product.setDescription("Product from Production"); return product; } }
Spring Integration Configuration
Knowing I want to unit test my Spring Integration Gateway, I’ve decided to split up my configuration files. There’s actually a couple different ways I could have approached this in Spring, such as using Profiles. However, for what I wish to accomplish today composing the Spring configuration works just fine.
si-product-gateway.xml
In this configuration I’m defining just the gateway and the channels. Nothing else.
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"> <gateway service-interface="guru.springframework.si.gateways.ProductGateway"/> <channel id="getProductChannel"/> </beans:beans>
si-config.xml
For my production configuration, I import the Spring Integration configuration and the provide the rest of my Spring configuration. This is the Spring Configuration file I will use for my production environment.
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <beans:import resource="classpath*:/spring/si-product-gateway.xml"/> <context:component-scan base-package="guru.springframework.si.testservice"/> <service-activator ref="productService" method="getProduct" input-channel="getProductChannel"/> </beans:beans>
Sprint Boot Application
Spring Boot makes it very easy to bring up the Spring context and execute our Spring Integration example application. In this class, you can see I’ve used the @SpringBootApplication
to bring up the Spring Context. I’m sourcing in the Spring Integration Configuration with the @ImportResource
annotation. When this this application runs, it will get the application context and ask for an instance of our Spring Integration Gateway. Notice in the above code, I never provided a concrete implementation of the Gateway interface. This is something that Spring Integration will do for you at run time. Once I have the ProductGateway
from the Spring context, I can ask it for a Product
.
package guru.springframework.si; import guru.springframework.si.gateways.ProductGateway; import guru.springframework.si.model.Product; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ImportResource; @SpringBootApplication @ImportResource("classpath*:/spring/si-config.xml") public class TestingSiGatewaysApplication { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(TestingSiGatewaysApplication.class, args); ProductGateway productGateway = (ProductGateway) ctx.getBean("productGateway"); Product product = productGateway.getProduct("1234"); System.out.println(product.getProductId()); System.out.println(product.getDescription()); } }
When you run this class, you will see this output:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.2.3.RELEASE) 2015-05-01 06:54:46.053 INFO 9434 --- [ main] g.s.si.TestingSiGatewaysApplication : Starting TestingSiGatewaysApplication on Johns-MacBook-Pro.local with PID 9434 (/Users/jt/src/springframework.guru/testing-si-gateways/target/classes started by jt in /Users/jt/src/springframework.guru/testing-si-gateways) 2015-05-01 06:54:46.624 INFO 9434 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3ecd23d9: startup date [Fri May 01 06:54:46 EDT 2015]; root of context hierarchy 2015-05-01 06:54:47.379 INFO 9434 --- [ main] o.s.b.f.xml.XmlBeanDefinitionReader : Loading XML bean definitions from URL [file:/Users/jt/src/springframework.guru/testing-si-gateways/target/classes/spring/si-config.xml] 2015-05-01 06:54:47.652 INFO 9434 --- [ main] o.s.b.f.xml.XmlBeanDefinitionReader : Loading XML bean definitions from URL [file:/Users/jt/src/springframework.guru/testing-si-gateways/target/classes/spring/si-product-gateway.xml] 2015-05-01 06:54:47.752 INFO 9434 --- [ main] o.s.b.f.config.PropertiesFactoryBean : Loading properties file from URL [jar:file:/Users/jt/.m2/repository/org/springframework/integration/spring-integration-core/4.1.2.RELEASE/spring-integration-core-4.1.2.RELEASE.jar!/META-INF/spring.integration.default.properties] 2015-05-01 06:54:47.759 INFO 9434 --- [ main] o.s.i.config.IntegrationRegistrar : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created. 2015-05-01 06:54:47.976 INFO 9434 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created. 2015-05-01 06:54:47.979 INFO 9434 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created. 2015-05-01 06:54:48.133 INFO 9434 --- [ main] o.s.b.f.config.PropertiesFactoryBean : Loading properties file from URL [jar:file:/Users/jt/.m2/repository/org/springframework/integration/spring-integration-core/4.1.2.RELEASE/spring-integration-core-4.1.2.RELEASE.jar!/META-INF/spring.integration.default.properties] 2015-05-01 06:54:48.133 INFO 9434 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationGlobalProperties' of type [class org.springframework.beans.factory.config.PropertiesFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-05-01 06:54:48.134 INFO 9434 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationGlobalProperties' of type [class java.util.Properties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-05-01 06:54:48.136 INFO 9434 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'messageBuilderFactory' of type [class org.springframework.integration.support.DefaultMessageBuilderFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-05-01 06:54:48.216 INFO 9434 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean '(inner bean)#4ba302e0' of type [class org.springframework.integration.channel.MessagePublishingErrorHandler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-05-01 06:54:48.217 INFO 9434 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler' 2015-05-01 06:54:48.219 INFO 9434 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'taskScheduler' of type [class org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-05-01 06:54:48.219 INFO 9434 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationHeaderChannelRegistry' of type [class org.springframework.integration.channel.DefaultHeaderChannelRegistry] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2015-05-01 06:54:48.342 INFO 9434 --- [ main] ProxyFactoryBean$MethodInvocationGateway : started productGateway 2015-05-01 06:54:48.343 INFO 9434 --- [ main] o.s.i.gateway.GatewayProxyFactoryBean : started productGateway 2015-05-01 06:54:49.068 INFO 9434 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup 2015-05-01 06:54:49.074 INFO 9434 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -2147483648 2015-05-01 06:54:49.076 INFO 9434 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0 2015-05-01 06:54:49.076 INFO 9434 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {service-activator} as a subscriber to the 'getProductChannel' channel 2015-05-01 06:54:49.076 INFO 9434 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.getProductChannel' has 1 subscriber(s). 2015-05-01 06:54:49.076 INFO 9434 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started org.springframework.integration.config.ConsumerEndpointFactoryBean#0 2015-05-01 06:54:49.076 INFO 9434 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel 2015-05-01 06:54:49.077 INFO 9434 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s). 2015-05-01 06:54:49.077 INFO 9434 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started _org.springframework.integration.errorLogger 2015-05-01 06:54:49.084 INFO 9434 --- [ main] g.s.si.TestingSiGatewaysApplication : Started TestingSiGatewaysApplication in 3.721 seconds (JVM running for 4.436) 1234 Product from Production 2015-05-01 06:54:49.106 INFO 9434 --- [ Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3ecd23d9: startup date [Fri May 01 06:54:46 EDT 2015]; root of context hierarchy 2015-05-01 06:54:49.108 INFO 9434 --- [ Thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0 2015-05-01 06:54:49.109 INFO 9434 --- [ Thread-1] ProxyFactoryBean$MethodInvocationGateway : stopped productGateway 2015-05-01 06:54:49.109 INFO 9434 --- [ Thread-1] o.s.i.gateway.GatewayProxyFactoryBean : stopped productGateway 2015-05-01 06:54:49.109 INFO 9434 --- [ Thread-1] o.s.i.endpoint.EventDrivenConsumer : Removing {service-activator} as a subscriber to the 'getProductChannel' channel 2015-05-01 06:54:49.109 INFO 9434 --- [ Thread-1] o.s.integration.channel.DirectChannel : Channel 'application.getProductChannel' has 0 subscriber(s). 2015-05-01 06:54:49.109 INFO 9434 --- [ Thread-1] o.s.i.endpoint.EventDrivenConsumer : stopped org.springframework.integration.config.ConsumerEndpointFactoryBean#0 2015-05-01 06:54:49.109 INFO 9434 --- [ Thread-1] o.s.i.endpoint.EventDrivenConsumer : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel 2015-05-01 06:54:49.110 INFO 9434 --- [ Thread-1] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 0 subscriber(s). 2015-05-01 06:54:49.110 INFO 9434 --- [ Thread-1] o.s.i.endpoint.EventDrivenConsumer : stopped _org.springframework.integration.errorLogger 2015-05-01 06:54:49.110 INFO 9434 --- [ Thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase -2147483648 2015-05-01 06:54:49.111 INFO 9434 --- [ Thread-1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown 2015-05-01 06:54:49.112 INFO 9434 --- [ Thread-1] o.s.s.c.ThreadPoolTaskScheduler : Shutting down ExecutorService 'taskScheduler'
Testing the Spring Boot Application
The Spring Boot Application, actually becomes a Spring Configuration. You can actually run this example as a JUnit Test.
package guru.springframework.si; import guru.springframework.si.gateways.ProductGateway; import guru.springframework.si.model.Product; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = TestingSiGatewaysApplication.class) public class TestingSiGatewaysApplicationTests { @Autowired ProductGateway productGateway; @Test public void contextLoads() { Product product = productGateway.getProduct("1234"); System.out.println(product.getProductId()); System.out.println(product.getDescription()); } }
Running this will produce the same output as above. While this is ‘testing’ our Spring Integration Gateway via JUnit, it is not really what we want. The configuration is still using our ‘production’ ProductService
.
Unit Testing The Spring Integration Gateway
Technically what I’m showing you is not a ‘Unit’ test. Many will argue once you bring up a Spring Context, your test is now an ‘Integration’ test. I’ll let you decide what to call it. To test my Spring Integration Gateway, I want to wire in a completely different service. In a real enterprise application, I would not want to be using the real product service for testing. I want to use some type of mock implementation.
Gateway Test Service
Here is the mock service I want to wire into my Spring Integration Gateway for testing. Very similar to the fake service I provided for our example above, in the fact that it just creates a Product
instance and returns it. For purposes of illustration, you can see I’m setting the product description to:
"Product in TESTING!!"
package guru.springframework.si.testservice; import guru.springframework.si.model.Product; import org.springframework.stereotype.Service; @Service public class GatewayTestService { private String lastString; public Product getProduct(String productId){ Product product = new Product(); product.setProductId(productId); product.setDescription("Product in TESTING!!"); return product; } public String getLastString() { return lastString; } public void setLastString(String lastString) { this.lastString = lastString; } }
Spring Configuration
Above I mentioned using composition for our Spring configuration in testing. Once you become more comfortable with the Spring Framework, you will find this is a very common technique to use. You will recall, I defined just the Spring Integration Gateway interface and channels in a Spring Integration file. For my unit tests, I can provide a completely different Spring Configuration. This in effect completely changes the plumbing behind the Spring Integration Gateway.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:integration="http://www.springframework.org/schema/integration" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"> <import resource="classpath*:/spring/si-product-gateway.xml"/> <context:component-scan base-package="guru.springframework.si.testservice"/> <integration:service-activator input-channel="getProductChannel" ref="gatewayTestService" method="getProduct"/> </beans>
JUnit Test of the Spring Integration Gateway
Here is a JUnit Test of the Spring Integration Gateway. In our test, we’re running it with the Spring JUnit Test Runner and specifying our test configuration for Spring.
package guru.springframework.si.gateway; import guru.springframework.si.gateways.ProductGateway; import guru.springframework.si.model.Product; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.junit.Assert.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath*:/spring/si-test-config.xml") public class ProductGatewayTests { @Autowired ProductGateway productGateway; @Test public void testGetProduct(){ Product product = productGateway.getProduct("33333"); assertNotNull(product); assertEquals("33333", product.getProductId()); System.out.println(product.getProductId()); System.out.println(product.getDescription()); } }
When you run the above test, it will pass the assertions. Also in the console you will see the following output:
07:23:40.988 [main] DEBUG o.s.i.h.ServiceActivatingHandler - ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor@6ccdb29f] received message: GenericMessage [payload=33333, headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3adcc812, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3adcc812, id=fd8d43a6-a45f-ef16-45a1-a1a45473323b, timestamp=1430479420988}] 07:23:40.993 [main] DEBUG o.s.i.channel.DirectChannel - postSend (sent=true) on channel 'getProductChannel', message: GenericMessage [payload=33333, headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3adcc812, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@3adcc812, id=fd8d43a6-a45f-ef16-45a1-a1a45473323b, timestamp=1430479420988}] 07:23:40.994 [main] DEBUG o.s.i.g.GatewayProxyFactoryBean - Unable to attempt conversion of Message payload types. Component 'productGateway' has no explicit ConversionService reference, and there is no 'integrationConversionService' bean within the context. 33333 Product in TESTING!! 07:23:40.997 [main] DEBUG o.s.t.c.s.DirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@a7e666 testClass = ProductGatewayTests, testInstance = guru.springframework.si.gateway.ProductGatewayTests@68bbe345, testMethod = testGetProduct@ProductGatewayTests, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@30b8a058 testClass = ProductGatewayTests, locations = '{classpath*:/spring/si-test-config.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false]. 07:23:41.001 [main] DEBUG o.s.t.c.s.DirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@a7e666 testClass = ProductGatewayTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@30b8a058 testClass = ProductGatewayTests, locations = '{classpath*:/spring/si-test-config.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false]. 07:23:41.004 [Thread-1] INFO o.s.c.s.GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext@3712b94: startup date [Fri May 01 07:23:40 EDT 2015]; root of context hierarchy 0
Notice how the product description is ‘Product In Testing’, proving that our test service was used, and not our ‘production’ service.
Spock Test of the Spring Integration Gateway
For fun, lets run the same test using Spock. Spock has become my favorite testing framework to use. If you’re not using Spock, you should be!
package guru.springframework.si.gateway import guru.springframework.si.gateways.ProductGateway import guru.springframework.si.model.Product import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.ContextConfiguration import spock.lang.Specification @ContextConfiguration(locations = "classpath*:/spring/si-test-config.xml") class ProductGatewaySpecTests extends Specification{ @Autowired ProductGateway productGateway def "Test get product gateway"() { given: def productId = '122222' when: Product product = productGateway.getProduct('122222') println product?.productId println product?.description then: product product.productId == productId } }
When you run the Spock Specification, you will see the following output:
07:29:33.359 [main] DEBUG o.s.i.channel.DirectChannel - postSend (sent=true) on channel 'getProductChannel', message: GenericMessage [payload=122222, headers={replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@222eb8aa, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@222eb8aa, id=30f5e380-47c9-7671-0bcc-6effb1666e78, timestamp=1430479773356}] 07:29:33.359 [main] DEBUG o.s.i.g.GatewayProxyFactoryBean - Unable to attempt conversion of Message payload types. Component 'productGateway' has no explicit ConversionService reference, and there is no 'integrationConversionService' bean within the context. 122222 Product in TESTING!! 07:29:33.376 [main] DEBUG o.s.t.c.s.DirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@4f83df68 testClass = ProductGatewaySpecTests, testInstance = guru.springframework.si.gateway.ProductGatewaySpecTests@6cf0e0ba, testMethod = $spock_feature_0_0@ProductGatewaySpecTests, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@7d8995e testClass = ProductGatewaySpecTests, locations = '{classpath*:/spring/si-test-config.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false]. 07:29:33.378 [main] DEBUG o.s.t.c.s.DirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@4f83df68 testClass = ProductGatewaySpecTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@7d8995e testClass = ProductGatewaySpecTests, locations = '{classpath*:/spring/si-test-config.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false].
Again, you can see all the assertions passed, and the output is ‘Product in Testing’.
Conclusion
Spring Integration Gateways are a great feature of Spring Integration. In this blog post, I’ve shown you how you can compose your Spring configuration files to change the behavior of Spring Integration for testing. I hope you can see how easy it is to wire up different configurations in Spring and Spring Integration.
Get The Code
I’ve committed the source code for this post to github. It is a Maven project which you can download and build. If you wish to learn more about the Spring Framework, I have a free introduction to Spring tutorial. You can sign up for this tutorial in the section below.