Testing with the Jersey Test Framework
Testing
Unit Tests
deal with atomic units of work, i.e.
- minimum units of work
- without any dependencies
Integration Tests
deal with logical units of works
- composed of multiple sub units
- that may be interdependent
Have an example
Hello Jersey
@Path("rest/hellojersey")
public class HelloJersey {
@GET
@Path("hello")
@Produces(MediaType.APPLICATION_JSON)
public Greeting getGreeting() {
return greetingDatabase.defaultGreeting();
}
@GET
@Path("echo/{echo}")
public Greeting getEcho(
@PathParam("echo") String echo) {
return new Greeting(new StringBuilder(echo)
.reverse().toString());
}
@GET
@Path("hello/store/{alias}")
@Produces(MediaType.APPLICATION_JSON)
public Greeting retrieveGreeting(
@PathParam("alias") String alias) {
return greetingStore.findGreeting(alias);
}
@POST
@Path("hello/store/{alias}")
@Consumes(MediaType.APPLICATION_JSON)
public void storeGreeting(
@PathParam("alias") String alias, Greeting greeting) {
greetingDatabase.storeGreeting(alias, greeting);
}
Hello Jersey API
{
"apiVersion":"1.0.0",
"swaggerVersion":"1.2",
"apis":
[
{
"path":"/hellojersey",
"description":"'Hello World'-style endpoint"
}
]
}
Testing strategies
- JUnit unit tests
- RESTassured
- Jersey Test Framework
JUnit
Setup
@Mock
GreetingDatabase greetingDatabase;
@InjectMocks
HelloJersey helloJersey;
@Before
public void setUp() {
helloJersey = new HelloJersey();
MockitoAnnotations.initMocks(this);
Mockito.when(greetingDatabase
.findGreeting(Mockito.anyString()))
.thenAnswer(invocation -> {
String name = (String) invocation.getArguments()[0];
if (name.equals("hawaii")) {
return new Greeting("Aloha!");
} else {
return new Greeting("Hello, I am a mock response.");
}
});
Mockito.when(greetingDatabase.defaultGreeting())
.thenAnswer(invocation -> new Greeting("Hello mock Jersey."));
@Test
public void testHello() {
assertEquals(new Greeting("Hello mock Jersey.").
getMessage(), helloJersey.getGreeting().getMessage());
}
@Test
public void testHelloEcho() {
assertEquals(new Greeting(new StringBuilder(
"Hello, I am a mock response.").reverse().toString())
.getMessage(),
helloJersey.getEcho("Hello, I am a mock response.")
.getMessage());
}
@Test
public void testRetrieveStoredGreeting() {
assertEquals(new Greeting(
"Hello, I am a mock response.").getMessage(),
helloJersey.retrieveGreeting
("anything").getMessage());
}
@Test
public void testStoreGreeting() {
Greeting greeting = new Greeting("Aloha!");
helloJersey.storeGreeting("hawaii", greeting);
assertEquals(helloJersey.retrieveGreeting("hawaii").
getMessage(), greeting.getMessage());
}
RESTassured
Setup
static boolean connectionExists = false;
@BeforeClass
public static void setUp() {
RestAssured.baseURI = "http://localhost";
RestAssured.port = 8080;
RestAssured.basePath = "/app";
try {
Response response = expect().statusCode(200)
.contentType(ContentType.JSON).when()
.get("/rest/hellojersey/hello");
String responseString =
new JsonPath(response.getBody().asString())
.getString("message");
connectionExists =
"Hello Jersey!".equals(responseString);
} catch (Exception e) {
}
}
@Test
public void testHello() {
assumeTrue(connectionExists);
Response response = expect().statusCode(200)
.contentType(ContentType.JSON).when()
.get("/rest/hellojersey/hello");
assertEquals("Hello Jersey!",
new JsonPath(response.getBody().asString())
.getString("message"));
}
@Test
public void testHelloEcho() {
assumeTrue(connectionExists);
Response response = given().pathParam("echo", "echo")
.expect().statusCode(200).when()
.get("/rest/hellojersey/echo/{echo}");
assertEquals("ohce",
new JsonPath(response.getBody().asString())
.getString("message"));
}
Jersey Test Framework
Setup
public class HelloJerseyJerseyTest extends JerseyTest {
@Mock
GreetingDatabase greetingDatabase;
@Override
protected Application configure() {
MockitoAnnotations.initMocks(this);
Mockito.when(greetingDatabase
.findGreeting(Mockito.anyString()))
.thenAnswer(invocation -> {
String name =
(String) invocation.getArguments()[0];
if (name.equals("hawaii")) {
return new Greeting("Aloha!");
} else {
return new Greeting("Hello, I am a mock response.");
}
});
Mockito.when(greetingDatabase.defaultGreeting())
.thenAnswer(invocation -> new Greeting("Hello mock Jersey!"));
Mockito.doNothing().when(greetingDatabase)
.storeGreeting(Mockito.anyString(), Mockito.any(Greeting.class));
...
Setup (continued)
...
// context injection will not work
//thus specify injection behaviour explicitly
resourceConfig.register(new AbstractBinder() {
@Override
protected void configure() {
bind(greetingDatabase).to(GreetingDatabase.class);
}
});
ResourceConfig resourceConfig =
new ResourceConfig(HelloJersey.class);
return resourceConfig;
}
@Test
public void testHelloObject() {
final String hello = target("rest/hellojersey/hello").
request().get(Greeting.class).getMessage();
assertEquals("Hello Jersey!", hello);
}
@Test
public void testHelloJSON() {
final String hello =
target("rest/hellojersey/hello")
.request().get().readEntity(String.class);
//overkill at this point, but a simple string
//comparison does not suffice for JSON
// - contents may be in any order
JsonParser parser = new JsonParser();
assertEquals(parser.parse(new Gson()
.toJson(new Greeting("Hello mock Jersey!"))),
parser.parse(hello));
}
@Test
public void testStoreGreeting() {
Greeting greeting = new Greeting("");
Entity<Greeting> entity =
Entity.entity(greeting, MediaType.APPLICATION_JSON_TYPE);
assertEquals(204,
target("rest/hellojersey/hello/store/newgreeting")
.request().post(entity).getStatus());
}
Conclusions
The Good
- fast (in memory container)
- very few dependencies (in memory container)
- proper REST endpoints
The Bad
- slow (external container)
- environmental dependencies (external container)
- no proper container environment (in memory)
The Ugly
- mocking requires context/dependency injection
- still no proper unit test
Miscanelleous
- slides.com/manuelweidmann/jerseytesting
- github.com/vyo/hellojersey
Testing with the Jersey Test Framework
By Manuel Weidmann
Testing with the Jersey Test Framework
- 787