Over a million developers have joined DZone.

Test your JAX-RS 2.0 Web Service URIs… Without Mocks

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.


After the announcement of the NoMock Movement I had to write another post about integration testing. Here it goes  : how to test your nice RESTful URIs ?

Use Case

Often you hear that URIs have to be expressive… and you want to test that your URIs are nicely written. How do you do that ? Unit testing with mock frameworks such as Restito or Rest assured ? If you do that you’ll be mocking the important part of what you really : a web server. Thanks to integration testing, you can just run your RESTful web service in an in memory web container and check that your URIs are correct (useful when you have many RESTful web services and get lost in your URIs)

JAX-RS 2.0 Client API

To integration-test URIs I will use the new JAX-RS 2.0 Client API and the Jersey implementation. If you haven’t followed what’s been happening, here are some news about JAX-RS. At the time of writing this post JAX-RS 2.0 is nearly out and will be in Java EE 7 by Q2 2013. The client API wasn’t standardized in JAX-RS 1.1 and it’s one of the novelties in 2.0. It allows you to make HTTP requests to your remote RESTful web services easily. It is a fluent request building API (i.e. using the Builder design pattern) that uses a small number of classes and interfaces which are in the javax.ws.rs.client package. The Client interface (obtained with the ClientFactory) is a builder of WebTarget instances. A WebTarget represents a distinct URI from which you can invoke requests on to obtain a Response. From this Response you can check HTTP status, length or cookies but more importantly you can get its content (a.k.a entity, message body or payload) through the Entity class.

With that in mind, here are the lines of code to invoke a GET method on a remote RESTful web service located at http://www.myserver.com/book and return a text/plain value:

Client client = ClientFactory.newClient();
WebTarget target = client.target("http://www.myserver.com/book");
Invocation invocation = target.request(MediaType.TEXT_PLAIN).buildGet();
Response response = invocation.invoke();

Thanks to the builder API and some shortcuts, you can write the same behavior in a single line of code:

Response response = ClientFactory.newClient().target("http://www.myserver.com/book").request(MediaType.TEXT_PLAIN).get();

RESTful Web Service

Let’s start with a simple RESTful web service with only GET methods. As you can see below, this service allows you to get a Customer by login (note the regular expression that only allows lowercase) and by ID (regular expression forces to have digits). Then there are two other methods that allow you to search customers by zip code (query param) or name and surname (matrix param).

public class CustomerRestService {

    @Path("{login: [a-z]*}")
    public Response getCustomerByLogin(@PathParam("login") String login) {
        Customer customer = new Customer("John", "Smith", "jsmith@gmail.com", "1234565");
        return Response.ok(customer).build();

    @Path("{customerId : \\d+}")
    public Response getCustomerById(@PathParam("customerId") Long id) {
        Customer customer = new Customer("John", "Smith", "jsmith@gmail.com", "1234565");
        return Response.ok(customer).build();

    public Response getCustomersByZipCode(@QueryParam("zip") Long zip) {
        Customers customers = new Customers();
        customers.add(new Customer("John", "Smith", "jsmith@gmail.com", "1234565"));
        customers.add(new Customer("John", "Smith", "jsmith@gmail.com", "1234565"));
        return Response.ok(customers).build();

    public Response getCustomerByName(@MatrixParam("firstname") String firstname, @MatrixParam("surname") String surname) {
        Customers customers = new Customers();
        customers.add(new Customer("John", "Smith", "jsmith@gmail.com", "1234565"));
        customers.add(new Customer("John", "Smith", "jsmith@gmail.com", "1234565"));
        return Response.ok(customers).build();

How to invoke these methods ?

And if you have a URI like /customer/AGONCAL it would be invalid because of the uppercase (the regex only allows lower cases).

Integration-Testing URIs

So let’s test these URIs in an integration test using a real HTTP server.

public class CustomerRestServiceIT {

    public void shouldCheckURIs() throws IOException {

        URI uri = UriBuilder.fromUri("http://localhost/").port(8282).build();

        // Create an HTTP server listening at port 8282
        HttpServer server = HttpServer.create(new InetSocketAddress(uri.getPort()), 0);
        // Create a handler wrapping the JAX-RS application
        HttpHandler handler = RuntimeDelegate.getInstance().createEndpoint(new ApplicationConfig(), HttpHandler.class);
        // Map JAX-RS handler to the server root
        server.createContext(uri.getPath(), handler);
        // Start the server

        Client client = ClientFactory.newClient();

        // Valid URIs
        assertEquals(200, client.target("http://localhost:8282/customer/agoncal").request().get().getStatus());
        assertEquals(200, client.target("http://localhost:8282/customer/1234").request().get().getStatus());
        assertEquals(200, client.target("http://localhost:8282/customer?zip=75012").request().get().getStatus());
        assertEquals(200, client.target("http://localhost:8282/customer/search;firstname=John;surname=Smith").request().get().getStatus());

        // Invalid URIs
        assertEquals(404, client.target("http://localhost:8282/customer/AGONCAL").request().get().getStatus());
        assertEquals(404, client.target("http://localhost:8282/customer/dummy/1234").request().get().getStatus());

        // Stop HTTP server

The idea is to launch an in-memory HTTP server. Jersey has several extensions so you can use Grizzly or GlassFish. But a very simple test would be to just use the com.sun.net.httpserver.HttpServer that comes with the Oracle JDK. As you can see in line 11, the only thing we need to do is to attach a com.sun.net.httpserver.HttpHandler with the JAX-RS application configuration (class ApplicationConfig not shown here, but you can download the code). Then you just need to start the in memory web server (server.start();), check your valid (return code 200) and invalid (return code 404) URIs and stop the server. That’s it.

I Gave a Quick Try at Unit-Test

I did give a try at unit testing this use case using  Restito. I have to be honest here, I’ve quickly looked at the developer’s guide and after struggling with Maven dependencies (REST Assured, Grizzly, Google Collections…) I managed to “unit test” my use case. I haven’t looked much into it but the logs from Restito looked a bit weired for a unit test :

org.glassfish.grizzly.http.server.NetworkListener start
org.glassfish.grizzly.http.server.HttpServer start
[HttpServer] Started
org.glassfish.grizzly.http.server.NetworkListener stop

So I don’t know if Restito is really starting Grizzly HTTP server of not, but if it is, it’s not really mocking much.


This integration-test will run in a few milliseconds (on my Mac, 3 secondes on a normal Windows XP box) and you will really check your URIs not mocking anything… But of course, this is a very simple test. Most of the time you need database access, injection and so on. That’s when when you bring Arquillian into play ;o) Maybe a topic to write about in a future post.


Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.


Published at DZone with permission of Antonio Goncalves, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}