diff --git a/README.adoc b/README.adoc
index c9f9b920d9a424e57f940077e23288d04330a529..c6f4b1b88e2b146bfd9636415f24f0b754497a88 100644
--- a/README.adoc
+++ b/README.adoc
@@ -136,6 +136,44 @@ $ curl localhost:8080
Greetings from Spring Boot!
....
+== Add Unit Tests
+
+You will want to add a test for the endpoint you added, and Spring Test already provides some machinery for that, and it's easy to include in your project.
+
+Add this to your build file's list of dependencies:
+
+[source,groovy]
+----
+include::complete/build.gradle[tag=tests]
+----
+
+If you are using Maven, add this to your list of dependencies:
+
+[source,xml]
+----
+include::complete/pom.xml[tag=tests]
+----
+
+Now write a simple unit test that mocks the servlet request and response through your endpoint:
+
+`src/test/java/hello/HelloControllerTest.java`
+[source,java]
+----
+include::initial/src/test/java/hello/HelloControllerTest.java[]
+----
+
+Note the use of the `MockServletContext` to set up an empty `WebApplicationContext` so the `HelloController` can be created in the `@Before` and passed to `MockMvcBuilders.standaloneSetup()`. An alternative would be to create the full application context using the `Application` class and `@Autowired` the `HelloController` into the test. The `MockMvc` comes from Spring Test and allows you, via a set of convenient builder classes, to send HTTP requests into the `DispatcherServlet` and make assertions about the result.
+
+As well as mocking the HTTP request cycle we can also use Spring Boot to write a very simple full-stack integration test. For example, instead of (or as well as) the mock test above we could do this:
+
+`src/test/java/hello/HelloControllerTest.java`
+[source,java]
+----
+include::initial/src/test/java/hello/HelloControllerIT.java[]
+----
+
+The embedded server is started up on a random port by virtue of the `@IntegrationTest("${server.port=0}")` and the actual port is discovered at runtime with the `@Value("${local.server.port}")`.
+
== Add production-grade services
If you are building a web site for your business, you probably need to add some management services. Spring Boot provides several out of the box with its http://docs.spring.io/spring-boot/docs/{spring_boot_version}/reference/htmlsingle/#production-ready[actuator module], such as health, audits, beans, and more.
diff --git a/complete/build.gradle b/complete/build.gradle
index 446ec000265a94d70342f5e4978b5af45017ccae..d101345e85894dabc5bbfeb59c85b517e5219545 100644
--- a/complete/build.gradle
+++ b/complete/build.gradle
@@ -26,7 +26,9 @@ dependencies {
// tag::actuator[]
compile("org.springframework.boot:spring-boot-starter-actuator")
// end::actuator[]
+ // tag::tests[]
testCompile("org.springframework.boot:spring-boot-starter-test")
+ // end::tests[]
}
task wrapper(type: Wrapper) {
diff --git a/complete/pom.xml b/complete/pom.xml
index eb8b8ee84490907340e8f978489145f2557ec0ac..801e46e01c7af7ee0655a3280a7795f199674a61 100644
--- a/complete/pom.xml
+++ b/complete/pom.xml
@@ -24,11 +24,13 @@
spring-boot-starter-actuator
+
org.springframework.boot
spring-boot-starter-test
test
+
diff --git a/complete/src/main/java/hello/HelloController.java b/complete/src/main/java/hello/HelloController.java
index fd7ed0a5d0adcb6359af9177cc8811e82f446a59..d9c1069cc5974931d491d6502ccb1d258663ad1c 100644
--- a/complete/src/main/java/hello/HelloController.java
+++ b/complete/src/main/java/hello/HelloController.java
@@ -6,7 +6,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
@RestController
public class HelloController {
- @RequestMapping("/hello")
+ @RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
diff --git a/complete/src/test/java/hello/HelloControllerIT.java b/complete/src/test/java/hello/HelloControllerIT.java
index 172896f9bf5f02c2f965f734921ea941c5a64831..ba1d64475447d8d6ad3139e779bf622d898af532 100644
--- a/complete/src/test/java/hello/HelloControllerIT.java
+++ b/complete/src/test/java/hello/HelloControllerIT.java
@@ -1,8 +1,14 @@
package hello;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.net.URL;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
@@ -11,22 +17,21 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestTemplate;
-import java.net.URL;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
-@IntegrationTest({"server.port=9090"})
+@IntegrationTest({"server.port=0"})
public class HelloControllerIT {
+
+ @Value("${local.server.port}")
+ private int port;
+
private URL base;
private RestTemplate template;
@Before
public void setUp() throws Exception {
- this.base = new URL("http://localhost:9090/hello");
+ this.base = new URL("http://localhost:" + port + "/");
template = new TestRestTemplate();
}
diff --git a/complete/src/test/java/hello/HelloControllerTest.java b/complete/src/test/java/hello/HelloControllerTest.java
index e0b450e39b8b22574aa6655f51a7b254ff30ad77..81fecad69cd3176c6ff8e3b1201cb0fb857cdd69 100644
--- a/complete/src/test/java/hello/HelloControllerTest.java
+++ b/complete/src/test/java/hello/HelloControllerTest.java
@@ -1,27 +1,26 @@
package hello;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockServletContext;
-import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import static org.hamcrest.Matchers.is;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
@RunWith(SpringJUnit4ClassRunner.class)
-@SpringApplicationConfiguration(classes = Application.class)
-@ContextConfiguration(classes = MockServletContext.class)
+@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
public class HelloControllerTest {
+
private MockMvc mvc;
@Before
@@ -31,7 +30,7 @@ public class HelloControllerTest {
@Test
public void getHello() throws Exception {
- mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
+ mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string(is("Greetings from Spring Boot!")));
}
diff --git a/initial/pom.xml b/initial/pom.xml
index 742a6309bf7b817957f7fd89126908866d30189a..96f104f1750eb8b5c60e60e957ab23ab1ef27aed 100644
--- a/initial/pom.xml
+++ b/initial/pom.xml
@@ -14,28 +14,10 @@
-
org.springframework.boot
spring-boot-starter-web
-
-
- org.springframework.boot
- spring-boot-starter-tomcat
-
-
-
- org.springframework.boot
- spring-boot-starter-jetty
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-