{"id":1015,"date":"2015-05-01T07:39:36","date_gmt":"2015-05-01T11:39:36","guid":{"rendered":"http:\/\/springframework.guru\/?p=1015"},"modified":"2019-06-24T21:20:32","modified_gmt":"2019-06-25T01:20:32","slug":"testing-spring-integration-gateways","status":"publish","type":"post","link":"https:\/\/springframework.guru\/testing-spring-integration-gateways\/","title":{"rendered":"Testing Spring Integration Gateways"},"content":{"rendered":"<p>Spring 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.<\/p>\n<p>What is nice about this approach, the complexities of the messaging layer is completely hidden from your application code. There is no &#8216;leakage&#8217; 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.<\/p>\n<h1>Spring Integration Gateway Example<\/h1>\n<h2>Overview<\/h2>\n<p>For our example today, lets say you&#8217;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&#8217;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.<\/p>\n<h3>Model<\/h3>\n<p>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.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si.model;\r\n\r\npublic class Product {\r\n    private String productId;\r\n    private String description;\r\n\r\n    public String getProductId() {\r\n        return productId;\r\n    }\r\n\r\n    public void setProductId(String productId) {\r\n        this.productId = productId;\r\n    }\r\n\r\n    public String getDescription() {\r\n        return description;\r\n    }\r\n\r\n    public void setDescription(String description) {\r\n        this.description = description;\r\n    }\r\n}\r\n<\/pre>\n<h3>Spring Integration Gateway<\/h3>\n<p>Here is the code for our Spring Integration Gateway. This is the interface you will use in your application.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si.gateways;\r\n\r\nimport guru.springframework.si.model.Product;\r\nimport org.springframework.integration.annotation.Gateway;\r\n\r\npublic interface ProductGateway {\r\n\r\n    @Gateway(requestChannel = \"getProductChannel\")\r\n    Product getProduct(String productId);\r\n}\r\n<\/pre>\n<h3>Product Service<\/h3>\n<p>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&#8217;d call to retrieve product data. I&#8217;ve created a very simple stub of a service class that just returns a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Product<\/code>\u00a0 object.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si.testservice;\r\n\r\nimport guru.springframework.si.model.Product;\r\nimport org.springframework.stereotype.Service;\r\n\r\n@Service\r\npublic class ProductService {\r\n    public Product getProduct(String productId) {\r\n        Product product = new Product();\r\n        product.setProductId(productId);\r\n        product.setDescription(\"Product from Production\");\r\n\r\n        return product;\r\n    }\r\n}\r\n<\/pre>\n<h3>Spring Integration Configuration<\/h3>\n<p>Knowing I want to unit test my Spring Integration Gateway, I&#8217;ve decided to split up my configuration files. There&#8217;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.<\/p>\n<h4>si-product-gateway.xml<\/h4>\n<p>In this configuration I&#8217;m defining just the gateway and the channels. Nothing else.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;beans:beans xmlns=\"http:\/\/www.springframework.org\/schema\/integration\"\r\n             xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n             xmlns:beans=\"http:\/\/www.springframework.org\/schema\/beans\"\r\n             xsi:schemaLocation=\"http:\/\/www.springframework.org\/schema\/beans\r\n                  http:\/\/www.springframework.org\/schema\/beans\/spring-beans.xsd\r\n                  http:\/\/www.springframework.org\/schema\/integration\r\n                  http:\/\/www.springframework.org\/schema\/integration\/spring-integration.xsd\"&gt;\r\n\r\n    &lt;gateway service-interface=\"guru.springframework.si.gateways.ProductGateway\"\/&gt;\r\n\r\n    &lt;channel id=\"getProductChannel\"\/&gt;\r\n\r\n&lt;\/beans:beans&gt;<\/pre>\n<h4>si-config.xml<\/h4>\n<p>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.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;beans:beans xmlns=\"http:\/\/www.springframework.org\/schema\/integration\"\r\n             xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n             xmlns:beans=\"http:\/\/www.springframework.org\/schema\/beans\"\r\n             xmlns:context=\"http:\/\/www.springframework.org\/schema\/context\"\r\n             xsi:schemaLocation=\"http:\/\/www.springframework.org\/schema\/beans\r\n                  http:\/\/www.springframework.org\/schema\/beans\/spring-beans.xsd\r\n                  http:\/\/www.springframework.org\/schema\/integration\r\n                  http:\/\/www.springframework.org\/schema\/integration\/spring-integration.xsd http:\/\/www.springframework.org\/schema\/context http:\/\/www.springframework.org\/schema\/context\/spring-context.xsd\"&gt;\r\n\r\n    &lt;beans:import resource=\"classpath*:\/spring\/si-product-gateway.xml\"\/&gt;\r\n\r\n    &lt;context:component-scan base-package=\"guru.springframework.si.testservice\"\/&gt;\r\n\r\n    &lt;service-activator ref=\"productService\" method=\"getProduct\" input-channel=\"getProductChannel\"\/&gt;\r\n&lt;\/beans:beans&gt;<\/pre>\n<h3>Sprint Boot Application<\/h3>\n<p>Spring Boot makes it very easy to bring up the Spring context and execute our Spring Integration example application.\u00a0 In this class, you can see I&#8217;ve used the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@SpringBootApplication<\/code>\u00a0 to bring up the Spring Context. I&#8217;m sourcing in the Spring Integration Configuration with the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">@ImportResource<\/code>\u00a0 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 <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductGateway<\/code>\u00a0 from the Spring context, I can ask it for a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Product<\/code>\u00a0.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si;\r\n\r\nimport guru.springframework.si.gateways.ProductGateway;\r\nimport guru.springframework.si.model.Product;\r\nimport org.springframework.boot.SpringApplication;\r\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\r\nimport org.springframework.context.ApplicationContext;\r\nimport org.springframework.context.annotation.ImportResource;\r\n\r\n@SpringBootApplication\r\n@ImportResource(\"classpath*:\/spring\/si-config.xml\")\r\npublic class TestingSiGatewaysApplication {\r\n\r\n    public static void main(String[] args) {\r\n        ApplicationContext ctx =  SpringApplication.run(TestingSiGatewaysApplication.class, args);\r\n        ProductGateway productGateway = (ProductGateway) ctx.getBean(\"productGateway\");\r\n        Product product = productGateway.getProduct(\"1234\");\r\n\r\n        System.out.println(product.getProductId());\r\n        System.out.println(product.getDescription());\r\n    }\r\n}\r\n<\/pre>\n<p>When you run this class, you will see this output:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">  .   ____          _            __ _ _\r\n \/\\\\ \/ ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\r\n( ( )\\___ | '_ | '_| | '_ \\\/ _` | \\ \\ \\ \\\r\n \\\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\r\n  '  |____| .__|_| |_|_| |_\\__, | \/ \/ \/ \/\r\n =========|_|==============|___\/=\/_\/_\/_\/\r\n :: Spring Boot ::        (v1.2.3.RELEASE)\r\n\r\n2015-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)\r\n2015-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\r\n2015-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]\r\n2015-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]\r\n2015-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]\r\n2015-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.\r\n2015-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.\r\n2015-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.\r\n2015-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]\r\n2015-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)\r\n2015-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)\r\n2015-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)\r\n2015-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)\r\n2015-05-01 06:54:48.217  INFO 9434 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService  'taskScheduler'\r\n2015-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)\r\n2015-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)\r\n2015-05-01 06:54:48.342  INFO 9434 --- [           main] ProxyFactoryBean$MethodInvocationGateway : started productGateway\r\n2015-05-01 06:54:48.343  INFO 9434 --- [           main] o.s.i.gateway.GatewayProxyFactoryBean    : started productGateway\r\n2015-05-01 06:54:49.068  INFO 9434 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup\r\n2015-05-01 06:54:49.074  INFO 9434 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147483648\r\n2015-05-01 06:54:49.076  INFO 9434 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0\r\n2015-05-01 06:54:49.076  INFO 9434 --- [           main] o.s.i.endpoint.EventDrivenConsumer       : Adding {service-activator} as a subscriber to the 'getProductChannel' channel\r\n2015-05-01 06:54:49.076  INFO 9434 --- [           main] o.s.integration.channel.DirectChannel    : Channel 'application.getProductChannel' has 1 subscriber(s).\r\n2015-05-01 06:54:49.076  INFO 9434 --- [           main] o.s.i.endpoint.EventDrivenConsumer       : started org.springframework.integration.config.ConsumerEndpointFactoryBean#0\r\n2015-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\r\n2015-05-01 06:54:49.077  INFO 9434 --- [           main] o.s.i.channel.PublishSubscribeChannel    : Channel 'application.errorChannel' has 1 subscriber(s).\r\n2015-05-01 06:54:49.077  INFO 9434 --- [           main] o.s.i.endpoint.EventDrivenConsumer       : started _org.springframework.integration.errorLogger\r\n2015-05-01 06:54:49.084  INFO 9434 --- [           main] g.s.si.TestingSiGatewaysApplication      : Started TestingSiGatewaysApplication in 3.721 seconds (JVM running for 4.436)\r\n1234\r\nProduct from Production\r\n2015-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\r\n2015-05-01 06:54:49.108  INFO 9434 --- [       Thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 0\r\n2015-05-01 06:54:49.109  INFO 9434 --- [       Thread-1] ProxyFactoryBean$MethodInvocationGateway : stopped productGateway\r\n2015-05-01 06:54:49.109  INFO 9434 --- [       Thread-1] o.s.i.gateway.GatewayProxyFactoryBean    : stopped productGateway\r\n2015-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\r\n2015-05-01 06:54:49.109  INFO 9434 --- [       Thread-1] o.s.integration.channel.DirectChannel    : Channel 'application.getProductChannel' has 0 subscriber(s).\r\n2015-05-01 06:54:49.109  INFO 9434 --- [       Thread-1] o.s.i.endpoint.EventDrivenConsumer       : stopped org.springframework.integration.config.ConsumerEndpointFactoryBean#0\r\n2015-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\r\n2015-05-01 06:54:49.110  INFO 9434 --- [       Thread-1] o.s.i.channel.PublishSubscribeChannel    : Channel 'application.errorChannel' has 0 subscriber(s).\r\n2015-05-01 06:54:49.110  INFO 9434 --- [       Thread-1] o.s.i.endpoint.EventDrivenConsumer       : stopped _org.springframework.integration.errorLogger\r\n2015-05-01 06:54:49.110  INFO 9434 --- [       Thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147483648\r\n2015-05-01 06:54:49.111  INFO 9434 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown\r\n2015-05-01 06:54:49.112  INFO 9434 --- [       Thread-1] o.s.s.c.ThreadPoolTaskScheduler          : Shutting down ExecutorService 'taskScheduler'\r\n<\/pre>\n<h2>Testing the Spring Boot Application<\/h2>\n<p>The Spring Boot Application, actually becomes a Spring Configuration. You can actually run this example as a JUnit Test.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si;\r\n\r\nimport guru.springframework.si.gateways.ProductGateway;\r\nimport guru.springframework.si.model.Product;\r\nimport org.junit.Test;\r\nimport org.junit.runner.RunWith;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.boot.SpringApplication;\r\nimport org.springframework.boot.test.SpringApplicationConfiguration;\r\nimport org.springframework.context.ApplicationContext;\r\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\r\n\r\n@RunWith(SpringJUnit4ClassRunner.class)\r\n@SpringApplicationConfiguration(classes = TestingSiGatewaysApplication.class)\r\npublic class TestingSiGatewaysApplicationTests {\r\n\r\n\t@Autowired\r\n\tProductGateway productGateway;\r\n\r\n\t@Test\r\n\tpublic void contextLoads() {\r\n\r\n\t\tProduct product = productGateway.getProduct(\"1234\");\r\n\r\n\t\tSystem.out.println(product.getProductId());\r\n\t\tSystem.out.println(product.getDescription());\r\n\t}\r\n\r\n}\r\n<\/pre>\n<p>Running this will produce the same output as above. While this is &#8216;testing&#8217; our Spring Integration Gateway via JUnit, it is not really what we want. The configuration is still using our &#8216;production&#8217; <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">ProductService<\/code>\u00a0.<\/p>\n<h2>Unit Testing The Spring Integration Gateway<\/h2>\n<p>Technically what I&#8217;m showing you is not a &#8216;Unit&#8217; test. Many will argue once you bring up a Spring Context, your test is now an &#8216;Integration&#8217; test. I&#8217;ll let you decide what to call it.\u00a0 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.<\/p>\n<h3>Gateway Test Service<\/h3>\n<p>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 <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">Product<\/code>\u00a0instance and returns it. For purposes of illustration, you can see I&#8217;m setting the product description to:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">\"Product in TESTING!!\"<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si.testservice;\r\n\r\nimport guru.springframework.si.model.Product;\r\nimport org.springframework.stereotype.Service;\r\n\r\n@Service\r\npublic class GatewayTestService {\r\n    private String lastString;\r\n\r\n    public Product getProduct(String productId){\r\n        Product product = new Product();\r\n        product.setProductId(productId);\r\n        product.setDescription(\"Product in TESTING!!\");\r\n        return product;\r\n    }\r\n\r\n    public String getLastString() {\r\n        return lastString;\r\n    }\r\n\r\n    public void setLastString(String lastString) {\r\n        this.lastString = lastString;\r\n    }\r\n}\r\n<\/pre>\n<h3>Spring Configuration<\/h3>\n<p>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.\u00a0For my unit tests, I can provide a completely different Spring Configuration. This in effect completely changes the plumbing behind the Spring Integration Gateway.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;beans xmlns=\"http:\/\/www.springframework.org\/schema\/beans\"\r\n       xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\r\n       xmlns:context=\"http:\/\/www.springframework.org\/schema\/context\"\r\n       xmlns:integration=\"http:\/\/www.springframework.org\/schema\/integration\"\r\n       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\"&gt;\r\n\r\n       &lt;import resource=\"classpath*:\/spring\/si-product-gateway.xml\"\/&gt;\r\n\r\n       &lt;context:component-scan base-package=\"guru.springframework.si.testservice\"\/&gt;\r\n\r\n       &lt;integration:service-activator input-channel=\"getProductChannel\" ref=\"gatewayTestService\" method=\"getProduct\"\/&gt;\r\n&lt;\/beans&gt;<\/pre>\n<h3>JUnit Test of the Spring Integration Gateway<\/h3>\n<p>Here is a JUnit Test of the Spring Integration Gateway. In our test, we&#8217;re running it with the Spring JUnit Test Runner and specifying our test configuration for Spring.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si.gateway;\r\n\r\nimport guru.springframework.si.gateways.ProductGateway;\r\nimport guru.springframework.si.model.Product;\r\nimport org.junit.Test;\r\nimport org.junit.runner.RunWith;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.test.context.ContextConfiguration;\r\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\r\nimport static org.junit.Assert.*;\r\n\r\n@RunWith(SpringJUnit4ClassRunner.class)\r\n@ContextConfiguration(locations = \"classpath*:\/spring\/si-test-config.xml\")\r\npublic class ProductGatewayTests {\r\n\r\n    @Autowired\r\n    ProductGateway productGateway;\r\n\r\n    @Test\r\n    public void testGetProduct(){\r\n        Product product = productGateway.getProduct(\"33333\");\r\n\r\n        assertNotNull(product);\r\n        assertEquals(\"33333\", product.getProductId());\r\n\r\n        System.out.println(product.getProductId());\r\n        System.out.println(product.getDescription());\r\n    }\r\n}\r\n<\/pre>\n<p>When you run the above test, it will pass the assertions. Also in the console you will see the following output:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">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}]\r\n07: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}]\r\n07: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.\r\n33333\r\nProduct in TESTING!!\r\n07: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].\r\n07: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].\r\n07: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\r\n0<\/pre>\n<p>Notice how the product description is &#8216;Product In Testing&#8217;, proving that our test service was used, and not our &#8216;production&#8217; service.<\/p>\n<h3>Spock Test of the Spring Integration Gateway<\/h3>\n<p>For fun, lets run the same test using Spock. Spock has become my favorite testing framework to use. If you&#8217;re not using Spock, you should be!<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\">package guru.springframework.si.gateway\r\n\r\nimport guru.springframework.si.gateways.ProductGateway\r\nimport guru.springframework.si.model.Product\r\nimport org.springframework.beans.factory.annotation.Autowired\r\nimport org.springframework.test.context.ContextConfiguration\r\nimport spock.lang.Specification\r\n\r\n@ContextConfiguration(locations = \"classpath*:\/spring\/si-test-config.xml\")\r\nclass ProductGatewaySpecTests extends Specification{\r\n\r\n    @Autowired\r\n    ProductGateway productGateway\r\n\r\n    def \"Test get product gateway\"() {\r\n        given:\r\n        def productId = '122222'\r\n\r\n        when:\r\n        Product product = productGateway.getProduct('122222')\r\n\r\n        println product?.productId\r\n        println product?.description\r\n\r\n        then:\r\n        product\r\n        product.productId == productId\r\n    }\r\n}\r\n<\/pre>\n<p>When you run the Spock Specification, you will see the following output:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"git\" data-enlighter-linenumbers=\"false\">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}]\r\n07: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.\r\n122222\r\nProduct in TESTING!!\r\n07: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].\r\n07: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].\r\n<\/pre>\n<p>Again, you can see all the assertions passed, and the output is &#8216;Product in Testing&#8217;.<\/p>\n<h1>Conclusion<\/h1>\n<p>Spring Integration Gateways are a great feature of Spring Integration. In this blog post, I&#8217;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.<\/p>\n<h2>Get The\u00a0Code<\/h2>\n<p>I&#8217;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.<\/p>\n\r\n\t<div class=\"df_call_to_action df_content_element cta_square\"  data-cta-class=\"normal\" data-cta-bg-color=\"#0F0F0F\" data-cta-border-color=\"#0F0F0F\">\r\n\t    <div class=\"cta_wrapper\">\r\n\t    \t<div class=\"cta_header\"><h3 style=\"color:#6cb44a !important;\">Source Code<\/h3><\/div>\r\n\t\t    <div class=\"cta_content\">The source code for this post is available on github. You can download it <a title=\"Testing Spring Integration Gateways\" href=\"https:\/\/github.com\/springframeworkguru\/testing-si-gateways\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>.<\/div>\r\n\t    <\/div>\r\n\t     \r\n\t<\/div>\r\n\n","protected":false},"excerpt":{"rendered":"<p>Spring 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 [&hellip;]<a href=\"https:\/\/springframework.guru\/testing-spring-integration-gateways\/\" class=\"df-link-excerpt\">Continue reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":4586,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Testing Spring Integration Gateways http:\/\/wp.me\/p5BZrZ-gn #Spring #springintegration #java","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[58],"tags":[],"class_list":["post-1015","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-spring-integration"],"jetpack_publicize_connections":[],"aioseo_notices":[],"modified_by":"Simanta","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/springframework.guru\/wp-content\/uploads\/2015\/03\/Banner560x292_03web.jpg","jetpack_shortlink":"https:\/\/wp.me\/p5BZrZ-gn","_links":{"self":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/1015"}],"collection":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/comments?post=1015"}],"version-history":[{"count":11,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/1015\/revisions"}],"predecessor-version":[{"id":5728,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/posts\/1015\/revisions\/5728"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/media\/4586"}],"wp:attachment":[{"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/media?parent=1015"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/categories?post=1015"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/springframework.guru\/wp-json\/wp\/v2\/tags?post=1015"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}