Skip to content

Commit f0f1f69

Browse files
committed
Polishing and Add Test
1 parent 4846b99 commit f0f1f69

File tree

8 files changed

+102
-7
lines changed

8 files changed

+102
-7
lines changed

README.adoc

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This guide walks you through the process of using Spring Integration to create a
1818

1919
== What you'll build
2020

21-
You'll create a flow using Spring Integration.
21+
You'll create a flow with Spring Integration using traditional XML configuration.
2222

2323
== What you'll need
2424

@@ -59,9 +59,15 @@ This simple flow is illustrated like this:
5959

6060
image::images/blogToFile.png[A flow that reads RSS feed entries, transforms them to a String, and appends them to a file.]
6161

62+
Ignore the `auto-startup` attribute for now; we'll revisit that later when discussing testing; just notice that it will be `true` by default which means the posts will be fetched when the application starts.
63+
Also note the property placeholder in the `filename-generator-expression`; this means the default will be `SpringBlog` but can be overridden with a property
64+
6265
== Make the application executable
6366

64-
Although it is common to configure a Spring Integration flow within a larger application, perhaps even a web application, there's no reason that it can't be defined in a simpler standalone application. That's what you do next, creating a main class that kicks off the integration flow and also declares a handful of beans to support the integration flow. You also build the application into a standalone executable JAR file. We use Spring Boot's `SpringApplication` to create the application context.
67+
Although it is common to configure a Spring Integration flow within a larger application, perhaps even a web application, there's no reason that it can't be defined in a simpler standalone application.
68+
That's what you do next, creating a main class that kicks off the integration flow and also declares a handful of beans to support the integration flow. You also build the application into a standalone executable JAR file.
69+
We use Spring Boot's `SpringApplication` to create the application context.
70+
Since this guide uses an the XML namespace for the integration flow, notice that we use `@ImportResource` to load it into the application context.
6571

6672

6773
`src/main/java/hello/Application.java`
@@ -100,8 +106,29 @@ Spring Integration Java DSL: Line by line tutorial @ https://spring.io/blog/2014
100106
Spring for Apache Hadoop 2.1.0.M2 Released @ https://spring.io/blog/2014/11/14/spring-for-apache-hadoop-2-1-0-m2-released
101107
....
102108

109+
== Testing
110+
111+
Examine the `complete` project and you will see a test case.
112+
113+
`src/test/java/hello/FlowTests.java`
114+
[source,java]
115+
----
116+
include::complete/src/test/java/hello/FlowTests.java[]
117+
----
118+
119+
This uses Spring Boot's test support to set a property `auto.startup` to `false`.
120+
It is generally not a good idea to rely on a network connection for tests, especially in a CI environment.
121+
So, instead, we prevent the feed adapter from starting and inject a `SyndEntry` into the `news` channel for processing by the rest of the flow.
122+
The test also sets the `feed.file.name` so the test writes to a different file; then:
123+
124+
- verifies the adapter is stopped
125+
- creates a test `SyndEntry`
126+
- deletes the test output file (if it's present)
127+
- sends the message
128+
- verifies the file exists
129+
- reads the file and verifies that the data is as expected
130+
103131
== Summary
104132
Congratulations! You have developed a simple application that uses Spring Integration to fetch blog posts from spring.io, process them, and write them to a file.
105133

106134
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/footer.adoc[]
107-

complete/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies {
2828
compile("org.springframework.boot:spring-boot-starter-integration")
2929
compile("org.springframework.integration:spring-integration-feed")
3030
compile("org.springframework.integration:spring-integration-file")
31+
testCompile("org.springframework.boot:spring-boot-starter-test")
3132
testCompile("junit:junit")
3233
}
3334

complete/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
<groupId>org.springframework.integration</groupId>
3232
<artifactId>spring-integration-file</artifactId>
3333
</dependency>
34+
35+
<dependency>
36+
<groupId>org.springframework.boot</groupId>
37+
<artifactId>spring-boot-starter-test</artifactId>
38+
<scope>test</scope>
39+
</dependency>
3440
</dependencies>
3541

3642

complete/src/main/java/hello/Application.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package hello;
22

33
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
45
import org.springframework.context.ConfigurableApplicationContext;
6+
import org.springframework.context.annotation.ImportResource;
57

8+
@SpringBootApplication
9+
@ImportResource("/hello/integration.xml")
610
public class Application {
711
public static void main(String[] args) throws Exception {
8-
ConfigurableApplicationContext ctx = new SpringApplication("/hello/integration.xml").run(args);
12+
ConfigurableApplicationContext ctx = new SpringApplication(Application.class).run(args);
913
System.out.println("Hit Enter to terminate");
1014
System.in.read();
1115
ctx.close();

complete/src/main/resources/hello/integration.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
1010
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
1111

12-
<feed:inbound-channel-adapter id="news" url="https://spring.io/blog.atom">
12+
<feed:inbound-channel-adapter id="news" url="http://spring.io/blog.atom" auto-startup="${auto.startup:true}">
1313
<int:poller fixed-rate="5000"/>
1414
</feed:inbound-channel-adapter>
1515

16-
<int:transformer
16+
<int:transformer
1717
input-channel="news"
1818
expression="payload.title + ' @ ' + payload.link + '#{systemProperties['line.separator']}'"
1919
output-channel="file"/>
@@ -22,6 +22,6 @@
2222
mode="APPEND"
2323
charset="UTF-8"
2424
directory="/tmp/si"
25-
filename-generator-expression="'SpringBlog'"/>
25+
filename-generator-expression="'${feed.file.name:SpringBlog}'"/>
2626

2727
</beans>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package hello;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.io.BufferedReader;
6+
import java.io.File;
7+
import java.io.FileReader;
8+
9+
import org.junit.Test;
10+
import org.junit.runner.RunWith;
11+
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
15+
import org.springframework.integration.support.MessageBuilder;
16+
import org.springframework.messaging.MessageChannel;
17+
import org.springframework.test.context.junit4.SpringRunner;
18+
19+
import com.rometools.rome.feed.synd.SyndEntryImpl;
20+
21+
@RunWith(SpringRunner.class)
22+
@SpringBootTest({ "auto.startup=false", // we don't want to start the real feed
23+
"feed.file.name=Test" }) // use a different file
24+
public class FlowTests {
25+
26+
@Autowired
27+
private SourcePollingChannelAdapter newsAdapter;
28+
29+
@Autowired
30+
private MessageChannel news;
31+
32+
@Test
33+
public void test() throws Exception {
34+
assertThat(this.newsAdapter.isRunning()).isFalse();
35+
SyndEntryImpl syndEntry = new SyndEntryImpl();
36+
syndEntry.setTitle("Test Title");
37+
syndEntry.setLink("http://foo/bar");
38+
File out = new File("/tmp/si/Test");
39+
out.delete();
40+
assertThat(out.exists()).isFalse();
41+
this.news.send(MessageBuilder.withPayload(syndEntry).build());
42+
assertThat(out.exists()).isTrue();
43+
BufferedReader br = new BufferedReader(new FileReader(out));
44+
String line = br.readLine();
45+
assertThat(line).isEqualTo("Test Title @ http://foo/bar");
46+
br.close();
47+
out.delete();
48+
}
49+
50+
}

initial/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies {
2828
compile("org.springframework.boot:spring-boot-starter-integration")
2929
compile("org.springframework.integration:spring-integration-feed")
3030
compile("org.springframework.integration:spring-integration-file")
31+
testCompile("org.springframework.boot:spring-boot-starter-test")
3132
testCompile("junit:junit")
3233
}
3334

initial/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
<groupId>org.springframework.integration</groupId>
3232
<artifactId>spring-integration-file</artifactId>
3333
</dependency>
34+
35+
<dependency>
36+
<groupId>org.springframework.boot</groupId>
37+
<artifactId>spring-boot-starter-test</artifactId>
38+
<scope>test</scope>
39+
</dependency>
3440
</dependencies>
3541

3642

0 commit comments

Comments
 (0)