DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Test your JAX-RS 2.0 Web Service URIs… Without Mocks

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

Antonio Goncalves user avatar by
Antonio Goncalves
·
Dec. 27, 12 · Interview
Like (0)
Save
Tweet
Share
19.90K Views

Join the DZone community and get the full member experience.

Join For Free

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).

@path("/customer")
@produces(mediatype.application_xml)
public class customerrestservice {

    @get
    @path("{login: [a-z]*}")
    public response getcustomerbylogin(@pathparam("login") string login) {
        customer customer = new customer("john", "smith", "jsmith@gmail.com", "1234565");
        customer.setlogin(login);
        return response.ok(customer).build();
    }

    @get
    @path("{customerid : \\d+}")
    public response getcustomerbyid(@pathparam("customerid") long id) {
        customer customer = new customer("john", "smith", "jsmith@gmail.com", "1234565");
        customer.setid(id);
        return response.ok(customer).build();
    }

    @get
    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();
    }

    @get
    @path("search")
    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 ?

  • /customer/agoncal invokes the getcustomerbylogin (get method and the path parameter only allows lowercases)
  • /customer/1234 invokes getcustomerbyid (get method and a numerical path parameter)
  • /customer?zip=75012 invokes getcustomersbyzipcode using queryparam
  • /customer/search;firstname=john;surname=smith invokes getcustomerbyname using matrixparam

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 {

    @test
    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
        server.start();

        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
        server.stop(0);
    }
}

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.

conclusion

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.

references

  • restito
  • rest assured


Web Service unit test

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

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Secrets Management
  • How To Generate Code Coverage Report Using JaCoCo-Maven Plugin
  • Writing a Modern HTTP(S) Tunnel in Rust
  • Quick Pattern-Matching Queries in PostgreSQL and YugabyteDB

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: