Last active
February 17, 2016 17:03
-
-
Save BenArunski/b27566dbdc9238f9459c to your computer and use it in GitHub Desktop.
Spring RestController + Rest-Assured + Spock
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
dependencies { | |
... | |
testCompile "org.hamcrest:hamcrest-library:1.3" | |
testCompile "org.hamcrest:hamcrest-core:1.3" | |
testCompile 'com.jayway.restassured:rest-assured:2.8.0' | |
testCompile 'com.jayway.restassured:spring-mock-mvc:2.8.0' | |
} | |
... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package hello; | |
import org.springframework.http.HttpStatus; | |
import org.springframework.web.bind.annotation.ResponseStatus; | |
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR, reason = "There was an unexpected server exception") | |
public class InternalServerErrorException extends RuntimeException { | |
private static final long serialVersionUID = 1L; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package hello; | |
public class Todo { | |
private String text; | |
private boolean done; | |
public Todo() { | |
} | |
public Todo(String text, boolean done) { | |
this.text = text; | |
this.done = done; | |
} | |
public void put(Todo todo) { | |
text = todo.text; | |
done = todo.done; | |
} | |
public String getText() { | |
return text; | |
} | |
public void setText(String text) { | |
this.text = text; | |
} | |
public boolean isDone() { | |
return done; | |
} | |
public void setDone(boolean done) { | |
this.done = done; | |
} | |
@Override | |
public int hashCode() { | |
final int prime = 31; | |
int result = 1; | |
result = prime * result + (done ? 1231 : 1237); | |
result = prime * result + ((text == null) ? 0 : text.hashCode()); | |
return result; | |
} | |
@Override | |
public boolean equals(Object obj) { | |
if (this == obj) | |
return true; | |
if (obj == null) | |
return false; | |
if (getClass() != obj.getClass()) | |
return false; | |
Todo other = (Todo) obj; | |
if (done != other.done) | |
return false; | |
if (text == null) { | |
if (other.text != null) | |
return false; | |
} else if (!text.equals(other.text)) | |
return false; | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package hello; | |
import static java.util.Collections.synchronizedList; | |
import static org.apache.http.HttpStatus.SC_BAD_REQUEST; | |
import static org.apache.http.HttpStatus.SC_NOT_FOUND; | |
import static org.apache.http.HttpStatus.SC_OK; | |
import static org.apache.http.HttpStatus.SC_UNPROCESSABLE_ENTITY; | |
import static org.springframework.web.bind.annotation.RequestMethod.DELETE; | |
import static org.springframework.web.bind.annotation.RequestMethod.GET; | |
import static org.springframework.web.bind.annotation.RequestMethod.POST; | |
import static org.springframework.web.bind.annotation.RequestMethod.PUT; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Map; | |
import javax.servlet.http.HttpServletResponse; | |
import org.apache.commons.lang3.BooleanUtils; | |
import org.springframework.web.bind.annotation.PathVariable; | |
import org.springframework.web.bind.annotation.RequestBody; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RestController; | |
@RestController | |
public class TodoController { | |
// List is just for demo purposes | |
private final List<Todo> todos = synchronizedList(new ArrayList<>()); | |
@RequestMapping(path = "/todos/{user}", method = { GET }, produces = "application/json") | |
public List<Todo> readAllForUser(@PathVariable("user") String user, HttpServletResponse response) { | |
if ("ben".equalsIgnoreCase(user)) { | |
response.setStatus(SC_OK); | |
return todos; | |
} else { | |
response.setStatus(SC_NOT_FOUND); | |
return new ArrayList<>(); | |
} | |
} | |
@RequestMapping(path = "/todo/{id}", method = { GET }, produces = "application/json") | |
public Todo read(@PathVariable("id") int id, HttpServletResponse response) { | |
try { | |
response.setStatus(SC_OK); | |
return todos.get(id); | |
} catch (IndexOutOfBoundsException e) { | |
response.setStatus(SC_NOT_FOUND); | |
return null; | |
} catch (Exception e) { | |
throw new InternalServerErrorException(); | |
} | |
} | |
@RequestMapping(path = "/todo", method = { POST }, produces = "application/json") | |
public List<Todo> create(@RequestBody Map<String, String> body, HttpServletResponse response) { | |
try { | |
if (body.get("text") != null) { | |
boolean done = BooleanUtils.toBoolean(body.get("done")); | |
todos.add(new Todo(body.get("text"), done)); | |
response.setStatus(SC_OK); | |
} else { | |
response.setStatus(SC_UNPROCESSABLE_ENTITY); | |
} | |
} catch (Exception e) { | |
throw new InternalServerErrorException(); | |
} | |
return todos; | |
} | |
@RequestMapping(path = "/todo", method = { DELETE }, produces = "application/json") | |
public synchronized List<Todo> deleteByObject(@RequestBody Todo body, HttpServletResponse response) { | |
try { | |
if (todos.remove(body)) { | |
response.setStatus(SC_OK); | |
} else { | |
response.setStatus(SC_NOT_FOUND); | |
} | |
} catch (Exception e) { | |
throw new InternalServerErrorException(); | |
} | |
return todos; | |
} | |
@RequestMapping(path = "/todo/{id}", method = { DELETE }, produces = "application/json") | |
public List<Todo> deleteById(@PathVariable("id") int id, HttpServletResponse response) { | |
try { | |
todos.remove(id); | |
response.setStatus(SC_OK); | |
} catch (IndexOutOfBoundsException e) { | |
response.setStatus(SC_NOT_FOUND); | |
} catch (Exception e) { | |
throw new InternalServerErrorException(); | |
} | |
return todos; | |
} | |
@RequestMapping(path = "/todo/{id}", method = { PUT }, produces = "application/json") | |
public List<Todo> update(@PathVariable("id") int id, @RequestBody Todo body, HttpServletResponse response) { | |
try { | |
todos.get(id).put(body); | |
response.setStatus(SC_OK); | |
} catch (IndexOutOfBoundsException e) { | |
response.setStatus(SC_NOT_FOUND); | |
} catch (Exception e) { | |
throw new InternalServerErrorException(); | |
} | |
return todos; | |
} | |
@RequestMapping(path = "/todo", method = { PUT }, produces = "application/json") | |
public List<Todo> updateByObject(@RequestBody List<Todo> body, HttpServletResponse response) { | |
try { | |
if (body.size() != 2) { | |
response.setStatus(SC_BAD_REQUEST); | |
} else { | |
response.setStatus(SC_NOT_FOUND); | |
todos.stream() | |
.filter(it -> it.equals(body.get(0))) | |
.findFirst() | |
.ifPresent(it -> { | |
it.put(body.get(1)); | |
response.setStatus(SC_OK); | |
}); | |
} | |
} catch (Exception e) { | |
throw new InternalServerErrorException(); | |
} | |
return todos; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package initial | |
import static com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.given | |
import static com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.when | |
import static org.hamcrest.Matchers.* | |
import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc | |
import com.jayway.restassured.module.mockmvc.specification.MockMvcRequestSpecification | |
import groovy.json.JsonBuilder | |
import hello.Todo | |
import hello.TodoController | |
import spock.lang.Specification | |
/** | |
* adapted from the final example on https://gist.github.com/kpiwko/5612949 | |
*/ | |
class todoControllerSpec extends Specification { | |
MockMvcRequestSpecification request = given().contentType("application/json") | |
JsonBuilder json = new JsonBuilder() | |
def setup() { | |
RestAssuredMockMvc.standaloneSetup(new TodoController()) | |
} | |
def 'get all for a user - empty' () { | |
given: 'get all for user' | |
def response = given().spec(request).get '/todos/ben' | |
def body = response.body() | |
expect: 'http success' | |
response.statusCode() == 200 | |
and: 'an empty set of todos' | |
body.path('$').size() == 0 | |
} | |
def 'create without done variable' () { | |
given: 'a todo body' | |
request.body json(text : 'the text') | |
when: 'a create request' | |
def response = given().spec(request).post "/todo" | |
def body = response.body() | |
then: 'http success' | |
response.statusCode() == 200 | |
and: 'one item is returned' | |
body.path('$').size() == 1 | |
and: 'my specified item is returned' | |
body.path('[0].text') == 'the text' | |
and: '"done" defaults false' | |
body.path('[0].done') == false | |
} | |
def 'get all for user - populated list' () { | |
given: 'two todos' | |
request.body json(text: 'one', done: true) | |
given().spec(request).post '/todo' | |
request.body json(text: 'two', done: false) | |
given().spec(request).post '/todo' | |
when: 'get all for user' | |
def response = given().spec(request).get '/todos/ben' | |
def body = response.body() | |
then: 'http success' | |
response.statusCode() == 200 | |
and: 'two items are returned' | |
body.path('$').size() == 2 | |
and: 'item 1 is returned' | |
Todo todo = body.path '[0]' | |
todo.text == 'one' | |
todo.done == true | |
and: 'item 2 is returned' | |
Todo todo2 = body.path '[1]' | |
todo2.text == 'two' | |
todo2.done == false | |
} | |
def 'update by id' () { | |
given: 'two todos' | |
request.body json(text: 'one', done: true) | |
given().spec(request).post '/todo' | |
request.body json(text: 'two', done: false) | |
given().spec(request).post '/todo' | |
when: 'update :1' | |
request.body json(text: 'updated one', done: true) | |
def response = given().spec(request).put '/todo/0' | |
def body = response.body() | |
then: 'http success' | |
response.statusCode() == 200 | |
and: 'item 1 is returned, updated' | |
Todo todo = body.path '[0]' | |
todo.text == 'updated one' | |
todo.done == true | |
and: 'item 2 is returned' | |
Todo todo2 = body.path '[1]' | |
todo2.text == 'two' | |
todo2.done == false | |
} | |
def 'update by object' () { | |
given: 'two todos' | |
request.body json(text: 'one', done: true) | |
given().spec(request).post '/todo' | |
request.body json(text: 'two', done: false) | |
given().spec(request).post '/todo' | |
when: 'update "one"' | |
request.body( | |
json ([ | |
[ | |
text: 'one', | |
done: true | |
], | |
[ | |
text: 'updated one', | |
done: true | |
] | |
]) | |
) | |
def response = given().spec(request).put '/todo' | |
def body = response.body() | |
then: 'http success' | |
response.statusCode() == 200 | |
and: 'item 1 is returned, updated' | |
Todo todo = body.path '[0]' | |
todo.text == 'updated one' | |
todo.done == true | |
and: 'item 2 is returned' | |
Todo todo2 = body.path '[1]' | |
todo2.text == 'two' | |
todo2.done == false | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package initial; | |
import static com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.given; | |
import static com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.when; | |
import static org.hamcrest.Matchers.equalTo; | |
import static org.hamcrest.Matchers.hasSize; | |
import org.junit.Before; | |
import org.junit.Test; | |
import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc; | |
import hello.TodoController; | |
/** | |
* Documentation: https://github.com/jayway/rest-assured/wiki/Usage#spring-mock-mvc-module | |
* | |
* Hints not in the official documentation: https://code.google.com/p/rest-assured/wiki/Usage#Request_Body | |
*/ | |
public class TodoControllerTest { | |
@Before | |
public void setup() { | |
RestAssuredMockMvc.standaloneSetup(new TodoController()); | |
} | |
@Test | |
public void canGetTodosForAUser() { | |
when() | |
.get("/todos/ben") | |
.then() | |
.statusCode(200) | |
.body("$", hasSize(0)); | |
} | |
@Test | |
public void canSaveATodo() { | |
String jsonRequestBody = "{ \"text\" : \"the text\" }"; | |
given() | |
.contentType("application/json") | |
.body(jsonRequestBody) | |
.when() | |
.post("/todo") | |
.then() | |
.statusCode(200) | |
.body("$", hasSize(1)) | |
.body("[0].text", equalTo("the text")); | |
when() | |
.get("/todos/ben"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment