From 3baac18c3e80a66d0c1a548dabba518a9dad0638 Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Sun, 3 Jan 2016 01:11:23 +0100 Subject: [PATCH] Spring REST, integration tests --- SpringJava/REST/README | 3 - SpringJava/REST/build.gradle | 33 --- SpringJava/REST/pom.xml | 272 +++++++++++++++++++++ .../main/java/de/spring/webservices/rest/Car.java | 20 ++ .../de/spring/webservices/rest/CarController.java | 87 +++++++ .../REST/src/main/java/rest/Application.java | 12 - SpringJava/REST/src/main/java/rest/Car.java | 20 -- .../REST/src/main/java/rest/CarController.java | 82 ------- SpringJava/REST/src/main/resources/log4j2.xml | 52 ++++ .../spring-configuration/mvc/rest/rest-config.xml | 54 ++++ .../spring-configuration/spring-config.xml | 13 + SpringJava/REST/src/main/webapp/WEB-INF/web.xml | 40 +++ .../rest/CarControllerIntegrationTest.java | 83 +++++++ 13 files changed, 621 insertions(+), 150 deletions(-) delete mode 100644 SpringJava/REST/README delete mode 100644 SpringJava/REST/build.gradle create mode 100644 SpringJava/REST/pom.xml create mode 100644 SpringJava/REST/src/main/java/de/spring/webservices/rest/Car.java create mode 100644 SpringJava/REST/src/main/java/de/spring/webservices/rest/CarController.java delete mode 100644 SpringJava/REST/src/main/java/rest/Application.java delete mode 100644 SpringJava/REST/src/main/java/rest/Car.java delete mode 100644 SpringJava/REST/src/main/java/rest/CarController.java create mode 100644 SpringJava/REST/src/main/resources/log4j2.xml create mode 100644 SpringJava/REST/src/main/resources/spring-configuration/mvc/rest/rest-config.xml create mode 100644 SpringJava/REST/src/main/resources/spring-configuration/spring-config.xml create mode 100644 SpringJava/REST/src/main/webapp/WEB-INF/web.xml create mode 100644 SpringJava/REST/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java diff --git a/SpringJava/REST/README b/SpringJava/REST/README deleted file mode 100644 index 2bd2c33..0000000 --- a/SpringJava/REST/README +++ /dev/null @@ -1,3 +0,0 @@ -gradle eclipse -gradle build -java -jar build/libs/rest-example-0.0.1.jar diff --git a/SpringJava/REST/build.gradle b/SpringJava/REST/build.gradle deleted file mode 100644 index ff56d4c..0000000 --- a/SpringJava/REST/build.gradle +++ /dev/null @@ -1,33 +0,0 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE") - } -} - -apply plugin: 'java' -apply plugin: 'eclipse-wtp' -apply plugin: 'spring-boot' - -jar { - baseName = 'rest-example' - version = '0.0.1' -} - -repositories { - mavenCentral() -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -dependencies { - compile("org.springframework.boot:spring-boot-starter-web") - testCompile("junit:junit") -} - -task wrapper(type: Wrapper) { - gradleVersion = '2.3' -} diff --git a/SpringJava/REST/pom.xml b/SpringJava/REST/pom.xml new file mode 100644 index 0000000..55c725b --- /dev/null +++ b/SpringJava/REST/pom.xml @@ -0,0 +1,272 @@ + + 4.0.0 + de.spring.webservices + web-services-spring-rest + war + 1.0-SNAPSHOT + web-services-spring-rest + http://gumartinm.name + Web Services REST Spring Framework + + Gustavo Martin Morcuende + http://www.gumartinm.name + + + scm:git:http://git.gumartinm.name/JavaForFun + http://git.gumartinm.name/JavaForFun + + + + UTF-8 + UTF-8 + 4.2.4.RELEASE + + + + + release + + release + + + true + + + + + + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.3 + + + + org.apache.logging.log4j + log4j-core + 2.3 + + + + org.slf4j + jcl-over-slf4j + 1.7.12 + + + + cglib + cglib + 2.2.2 + + + org.springframework + spring-core + ${spring.version} + + + + commons-logging + commons-logging + + + + + org.springframework + spring-webmvc + ${spring.version} + + + + commons-logging + commons-logging + + + + + + + javax.servlet + javax.servlet-api + 4.0.0-b01 + provided + + + + + com.fasterxml.jackson.core + jackson-databind + 2.6.4 + + + + + javax.validation + validation-api + 1.1.0.Final + + + org.hibernate + hibernate-validator + 5.2.2.Final + + + + + + junit + junit + 4.12 + test + + + org.springframework + spring-test + ${spring.version} + test + + + org.mockito + mockito-core + 2.0.11-beta + test + + + + + org.hamcrest + hamcrest-core + 1.3 + test + + + org.hamcrest + hamcrest-library + 1.3 + test + + + com.jayway.jsonpath + json-path + 2.1.0 + test + + + + + ${project.artifactId} + + + ${basedir}/src/main/webapp + + **/*.* + + + + ${basedir}/src/main/resources/ + + **/*.* + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${project.description} + ${project.version} + ${project.organization.name} + ${project.description} + ${project.version} + ${project.organization.name} + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + **/*IntegrationTest.java + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.18.1 + + + + integration-test + verify + + + + + + **/*IntegrationTest.java + + + + + org.apache.maven.plugins + maven-war-plugin + 2.6 + + + + true + src/main/webapp + + WEB-INF/web.xml + + + + + + + + diff --git a/SpringJava/REST/src/main/java/de/spring/webservices/rest/Car.java b/SpringJava/REST/src/main/java/de/spring/webservices/rest/Car.java new file mode 100644 index 0000000..2dafc8d --- /dev/null +++ b/SpringJava/REST/src/main/java/de/spring/webservices/rest/Car.java @@ -0,0 +1,20 @@ +package de.spring.webservices.rest; + +public class Car { + + private final Long id; + private final String content; + + public Car(Long id, String content) { + this.id = id; + this.content = content; + } + + public Long getId() { + return id; + } + + public String getContent() { + return content; + } +} diff --git a/SpringJava/REST/src/main/java/de/spring/webservices/rest/CarController.java b/SpringJava/REST/src/main/java/de/spring/webservices/rest/CarController.java new file mode 100644 index 0000000..e566d91 --- /dev/null +++ b/SpringJava/REST/src/main/java/de/spring/webservices/rest/CarController.java @@ -0,0 +1,87 @@ +package de.spring.webservices.rest; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/cars/") +public class CarController { + private static final Logger LOGGER = LoggerFactory.getLogger(CarController.class); + private static final String TEMPLATE = "Car: %s"; + + private final AtomicLong counter = new AtomicLong(); + + @RequestMapping(produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }, method = RequestMethod.GET) + @ResponseStatus(HttpStatus.OK) + public List cars() { + final List cars = new ArrayList<>(); + cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 1))); + cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 2))); + cars.add(new Car(counter.incrementAndGet(), String.format(TEMPLATE, 3))); + + return cars; + } + + @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET) + @ResponseStatus(HttpStatus.OK) + public Car car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader, + @PathVariable("id") long id, + @RequestParam Map params, + @RequestParam(value = "wheel", required = false) String[] wheelParams) { + + if (specialHeader != null) { + LOGGER.info("SPECIAL HEADER: " + specialHeader); + } + + if (params.get("mirror") != null) { + LOGGER.info("MIRROR: " + params.get("mirror")); + } + + if (params.get("window") != null) { + LOGGER.info("WINDOW: " + params.get("window")); + } + + if (wheelParams != null) { + for(String wheel : wheelParams) { + LOGGER.info(wheel); + } + } + + try { + Thread.sleep(10000); //1000 milliseconds is one second. + } catch(InterruptedException ex) { + Thread.currentThread().interrupt(); + } + + + return new Car(counter.incrementAndGet(), String.format(TEMPLATE, id)); + } + + @RequestMapping(consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, + produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST) + public ResponseEntity create(@RequestBody Car car) { + long count = counter.incrementAndGet(); + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.LOCATION, "/api/cars/" + count); + + return new ResponseEntity<>(new Car(count, String.format(TEMPLATE, count)), headers, HttpStatus.CREATED); + } + +} diff --git a/SpringJava/REST/src/main/java/rest/Application.java b/SpringJava/REST/src/main/java/rest/Application.java deleted file mode 100644 index 808c3ab..0000000 --- a/SpringJava/REST/src/main/java/rest/Application.java +++ /dev/null @@ -1,12 +0,0 @@ -package rest; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/SpringJava/REST/src/main/java/rest/Car.java b/SpringJava/REST/src/main/java/rest/Car.java deleted file mode 100644 index 06edef1..0000000 --- a/SpringJava/REST/src/main/java/rest/Car.java +++ /dev/null @@ -1,20 +0,0 @@ -package rest; - -public class Car { - - private final long id; - private final String content; - - public Car(long id, String content) { - this.id = id; - this.content = content; - } - - public long getId() { - return id; - } - - public String getContent() { - return content; - } -} diff --git a/SpringJava/REST/src/main/java/rest/CarController.java b/SpringJava/REST/src/main/java/rest/CarController.java deleted file mode 100644 index e8d2f17..0000000 --- a/SpringJava/REST/src/main/java/rest/CarController.java +++ /dev/null @@ -1,82 +0,0 @@ -package rest; - -import java.util.concurrent.atomic.AtomicLong; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/api/cars/") -public class CarController { - - private static final String template = "Car: %s"; - private final AtomicLong counter = new AtomicLong(); - - @RequestMapping(produces = { "application/json" }, method = RequestMethod.GET) - @ResponseStatus(HttpStatus.OK) - public List cars() { - final List cars = new ArrayList<>(); - cars.add(new Car(counter.incrementAndGet(), String.format(template, 1))); - cars.add(new Car(counter.incrementAndGet(), String.format(template, 2))); - cars.add(new Car(counter.incrementAndGet(), String.format(template, 3))); - - return cars; - } - - @RequestMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET) - @ResponseStatus(HttpStatus.OK) - public Car car(@RequestHeader(value = "MY_HEADER", required = false) String specialHeader, - @PathVariable("id") long id, - @RequestParam Map params, - @RequestParam(value = "wheel", required = false) String[] wheelParams) { - - if (specialHeader != null) { - System.out.println("SPECIAL HEADER: " + specialHeader); - } - - if (params.get("mirror") != null) { - System.out.println("MIRROR: " + params.get("mirror")); - } - - if (params.get("window") != null) { - System.out.println("WINDOW: " + params.get("window")); - } - - if (wheelParams != null) { - for(String wheel : wheelParams) { - System.out.println(wheel); - } - } - - try { - Thread.sleep(10000); //1000 milliseconds is one second. - } catch(InterruptedException ex) { - Thread.currentThread().interrupt(); - } - - - return new Car(counter.incrementAndGet(), String.format(template, id)); - } - - @RequestMapping(consumes = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST) - public ResponseEntity create() { - HttpHeaders headers = new HttpHeaders(); - headers.add("Location", "/api/cars/" + 1); - - return new ResponseEntity<>(new Car(counter.incrementAndGet(), String.format(template, 1)), headers, HttpStatus.CREATED); - } - -} diff --git a/SpringJava/REST/src/main/resources/log4j2.xml b/SpringJava/REST/src/main/resources/log4j2.xml new file mode 100644 index 0000000..ee36b97 --- /dev/null +++ b/SpringJava/REST/src/main/resources/log4j2.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SpringJava/REST/src/main/resources/spring-configuration/mvc/rest/rest-config.xml b/SpringJava/REST/src/main/resources/spring-configuration/mvc/rest/rest-config.xml new file mode 100644 index 0000000..5f706e6 --- /dev/null +++ b/SpringJava/REST/src/main/resources/spring-configuration/mvc/rest/rest-config.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SpringJava/REST/src/main/resources/spring-configuration/spring-config.xml b/SpringJava/REST/src/main/resources/spring-configuration/spring-config.xml new file mode 100644 index 0000000..af3643b --- /dev/null +++ b/SpringJava/REST/src/main/resources/spring-configuration/spring-config.xml @@ -0,0 +1,13 @@ + + + + diff --git a/SpringJava/REST/src/main/webapp/WEB-INF/web.xml b/SpringJava/REST/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..26089bd --- /dev/null +++ b/SpringJava/REST/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,40 @@ + + + + Spring REST Services: example + + + + org.springframework.web.context.ContextLoaderListener + + + + + spring.profiles.active + ${environment.profile} + contextConfigLocation + + classpath*:spring-configuration/*.xml + + + + + + spring-rest + org.springframework.web.servlet.DispatcherServlet + 1 + true + + contextConfigLocation + classpath*:spring-configuration/mvc/rest/*.xml + + + + + spring-rest + /spring-rest/* + + + diff --git a/SpringJava/REST/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java b/SpringJava/REST/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java new file mode 100644 index 0000000..a19ecc3 --- /dev/null +++ b/SpringJava/REST/src/test/java/de/spring/webservices/rest/CarControllerIntegrationTest.java @@ -0,0 +1,83 @@ +package de.spring.webservices.rest; + +import static org.hamcrest.Matchers.any; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +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.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ "classpath*:spring-configuration/mvc/rest/*.xml"}) +public class CarControllerIntegrationTest { + private CarController controller; + private MockMvc mockMvc; + + @Before + public void setup() { + controller = new CarController(); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + public void testWhenGetAllCarsThenRetrieveJsonValues() throws Exception { + mockMvc.perform(get("/api/cars/") + .accept(MediaType.APPLICATION_JSON_UTF8_VALUE)) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id", any(Integer.class))) + .andExpect(jsonPath("$[0].content", is("Car: 1"))) + .andExpect(jsonPath("$[1].content", is("Car: 2"))) + .andExpect(jsonPath("$[1].id", any(Integer.class))) + .andExpect(jsonPath("$[2].content", is("Car: 3"))) + .andExpect(jsonPath("$[2].id", any(Integer.class))) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } + +// @Test +// public void testWhenGetOneCarThenRetrieveJsonValue() throws Exception { +// mockMvc.perform(get("/api/cars/{id}", 1L) +// .accept(MediaType.APPLICATION_JSON_UTF8_VALUE)) +// +// .andExpect(status().isOk()) +// .andExpect(jsonPath("id", any(Integer.class))) +// .andExpect(jsonPath("content", is("Car: 1"))) +// .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); +// } + + @Test + public void testWhenCreateNewCarThenRetrieveJsonValue() throws Exception { + Car car = new Car(2L, "nothing"); + mockMvc.perform(post("/api/cars/") + .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) + .content(asJsonString(car)) + .accept(MediaType.APPLICATION_JSON_UTF8_VALUE)) + + .andExpect(status().isCreated()) + .andExpect(jsonPath("id", any(Integer.class))) + .andExpect(jsonPath("content", is("Car: 1"))) + .andExpect(header().string(HttpHeaders.LOCATION, "/api/cars/1")) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)); + } + + private static String asJsonString(final Object obj) throws JsonProcessingException { + final ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(obj); + } +} -- 2.1.4