Rest-assured is a 100% java-based, BDD style, test library that you can use for testing REST api's in java projects. These are the slides from the presentation and demo I give at the 2017 #JBCNConf Java conference in Barcelona.
4. Contents
• Rest testing Context
• Rest-Assured
Introduction
Demo
Other features
• Integration with Spring / SpringBoot
Mocking dependencies
• Wrapup
• Q&A
5. Who here...
...is developing (micro/ buzzword) services?
...is working with REST interfaces on a daily basis?
...uses automated testing for their REST interfaces?
6. What is REST testing?
Component test against the REST boundary of your service
Conference
service
REST api
GET /conference/1 { “name” : “JBCNConf2017”,
“Description”: “best Java conference in
the world!”
“begins”: “19-06-2017”
“ends”: “21-06-2017”
“city”: “Barcelona”
}
Test framework
7. Types of tests
Out-of-process tests
Tests against your deployed artifact
In-process tests
Tests against your artifact in-memory
Contract tests
Out-of-process tests against someone else’s api
(either deployed or stubbed)
Test framework
Conference
service memdb
In-memory call
Test framework
Conference
service db
network url
network
Test framework
Other service
9. Testing REST api’s with
Scenario: Conference service should return JBCNConf Conference
Given a running conference service
When request conference “1”
Then it should return a conference
And the attribute "name" should be "JBCNConf2017"
Feature
file
Glue
code +
httpclient
Conference
service
R
E
S
T
10. Testing REST api’s with
private RestInterface restInterface;
@When("request conference d")
public void requestConference(int id) {
Map<String,String> map = new HashMap<>();
map.put("id", String.valueOf(id));
restInterface.setURIParameters(map);
restInterface.callRestService();
}
@Then("it should return a conference")
public void thenConferenceIsReturned() {
assertEquals(200, restInterface.getStatusCode());
}
@And("the attribute s should be s")
public void theAttributeShouldBe(String name, String value) {
String json = restInterface.getJSON();
//parsing and asserting stuff
}
11. Enter
• Developed and maintained by Johan Haleby (launched dec 2010)
• Rest-testing in a JUnit fashion
• 100% Java DSL api (Groovy underneath)
• Uses GPath for simplifying asserts, making testing just as easy like in Groovy!
• Focuses on testing with a concise, BDD-like syntax
• Really helped us to reduce boilerplate and write readable tests very quickly!
13. import static io.restassured.RestAssured.*;
@Test
public void restServiceShouldProduceResponse() {
given().
…. Setting up request, params, headers, cookies, auth…
when().
.... calling a URL through GET, POST, etc…
then().
...assert a bunch of stuff
}
Writing a test
14.
15. Back to our conference service
import static io.restassured.RestAssured.when;
import static org.hamcrest.CoreMatchers.equalTo;
import org.junit.Test;
public class ConferenceRestIT {
@Test
public void test() {
given().
when().
get("/conference/{id}", 1).
then().
statusCode(200).
body("name", equalTo("JBCNConf2017"));
}
}
29. Extracting data
@Test
public void extractJBCNConference() {
String response = when()
.get("/conference/{id}", 1)
.then()
.extract()
.asString();
System.out.println(response);
}
You can extracts response, paths, cookies, headers etc.
30. Reusing request and response setups
RequestSpecBuilder requestSpecBuilder = new RequestSpecBuilder();
requestSpecBuilder.setContentType("application/json");
ResponseSpecBuilder responseSpecBuilder = new ResponseSpecBuilder();
responseSpecBuilder.expectStatusCode(200);
given().
spec(requestSpecBuilder.build()).
when().
get("/conference").
then().
spec(responseSpecBuilder.build());
You can merge specs and arbitrary params /
headers / cookies etc.
40. Defaults
Rest-assured goes to localhost, port 8080
You can change this behaviour:
given.port(80).when(....
RestAssured.port = 80;
With a Request spec builder
Same goes for host, baseURI, basePath, etc…
Easy to make this flexible by system property
given.port(System.getProperty(“server.port”)).when(...
42. Integration with Spring
● Just use a @SpringBootTest IT test
● It will spin up a SpringBoot app
● Out-of-process testing, so just use RestAssured as you would
normally do
@SpringBootTest
SpringBoot Conference
service db
network url
network
43. Integration with traditional Spring application
● Use a normal Spring IT test
● Since this is in-process, you need to connect to the Dispatcher in some way
● Use the RestAssuredMockMvc class instead of RestAssured
● Wrapper around Spring MockMvc testing framework
● Slightly different programming model, however...
SpringIT test
SpringApp memdb
In-memory call
JVM
44. Mocking dependencies
Your service depends on some other service
ConferenceService
SpeakerService
TestFramework
SpeakerServiceMock
Mock out dependencies during testing
45. Spring Boot example
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource("classpath:test.properties")
public class SpringBootRestIT {
@LocalServerPort
private int randomServerPort;
@Test
public void testJBCNConference() {
given().
port(randomServerPort).
log().all().
when().
get("/conference/{id}", 1).
then().
statusCode(200).
}
46. Traditional Spring example
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ConferenceApplication.class})
@WebAppConfiguration
public class TraditionalSpringIT {
@Autowired
private WebApplicationContext context;
@Before
public void
rest_assured_is_initialized_with_the_web_application_context_before_each_test() {
RestAssuredMockMvc.webAppContextSetup(context);
}
@After
public void
rest_assured_is_reset_after_each_test() {
RestAssuredMockMvc.reset();
}
@Test
public void testJBCNConference() {
RestAssuredMockMvc.when().
get("/conference/{id}", 1).
then().
statusCode(200).
body("name", equalTo("JBCNConf2017"));
}
47. Using WireMock
private WireMockServer wireMockServer;
@Before
public void setup() {
startWireMockServer();
wireMockServer.stubFor(get(anyUrl()).willReturn(buildResponse()));
}
private ResponseDefinitionBuilder buildResponse() {
return responseDefinitionBuilder;
}
private void startWireMockServer() {
URI uri = URI.create(speakerEndpoint);
wireMockServer = new WireMockServer(options().port(8081));
wireMockServer.start();
}
@After
public void tearDown() {
wireMockServer.stop();
}
49. Pros and cons
● Writing a REST test takes minutes
● Really easy to read
● Flexible programming model (json/xml agnostic, free chaining of methods)
● Works well in-process (Spring IT) and out-of-process (SpringBoot)
● (Relatively) fast feedback
Contract testing
● You could use RestAssured for that, but you need a running instance
● Pact / Spring Cloud Contract are better solutions
Improvements
● If only someone could write a good code formatter….
This is way better. But there is some discussion on how businessy this should be. Should it read “it should return a conference”? Or “status code should be 200”, or something like that?
Still have to write step defs, glue code...so this is still a lot of work.
This is way better. But there is some discussion on how businessy this should be. Should it read “it should return a conference”? Or “status code should be 200”, or something like that?
Still have to write step defs, glue code...so this is still a lot of work.