Wink clients and Unit Testing JAX-RS Services

December 4, 2009

In a previous posting I described how I exercised my RESTful services using the Firefox extension Poster and also by calling the service from JavaScript in the browser using the Dojo framework. Poster is especially useful because we can very quickly exercise a service. However for testing I want something more:

  1. To repeatedly run a set of tests covering a variety of inputs.
  2. To specify expected outcomes for these test. Using just Poster I must inspect the values by eye, which is error prone.

In other words I want to use a tool such as JUnit. To do that we need to be able to write Java clients of our RESTful services. This is not something directly addressed by the JAX-RS specification, however the Apache Wink framework does include APIs that enable writing clients of a RESTful service. So in the remainder of this post I will explain how I created tests for my service.

Wink Libraries

Previously, when using Wink in a JEE application deployed to WebSphere I copied Wink libraries into WEB-INF/lib directory of the Web Application, and hence these libraries were available at both compile time and runtime. The JUnit tests run as stand-alone Java applications and can pick up the Wink libraries from classpaths specified in RAD. There’s quite a few ways of doing that, for example simply referring to the JARs whereever Apache Wink was downloaded, or creating a User Library. My preference is to set up projects that can be checked into CVS and checked out by any developer, with no dependencies on external downloads.

Hence I created an Apache Wink project and copied the Wink download to that project.

ApacheWinkProj

I then set up the project build path to refer to the JARs needed from that project. I select the project and then

    rightClick –> Properties –> Java Build Path –> Libraries Tab

Then Add Jars and select JAR files from the Apache Wink project.

ClientBuildPath

These JARs include the APIs we use directly and so are needed on the Build Path

    jsr311-api-1.0.jar
    wink-client-1.0-incubating.jar
    wink-common-1.0-incubating.jar

Additionally, we need the JSON and logging libraries at runtime. It’s convenient to add these libraries to the Build Path (even though we don’t need them at build time) because then simple “Run As” commands pick up the correct runtime classpath.

    slf4j-api-1.5.8.jar
    slf4j-simple-1.5.8.jar (or slf4j-jdk14-1.5.8.jar from here)

    json-20080701.jar
    wink-json-provider-1.0-incubating.jar

Note that If we now check the ApacheWink and the test project into CVS we can create a Project Set File for those two projects which can be checked out by any developer and they immediately have a complete working test program, with no external dependencies.

Next I completed setting up the Build Path by enabling the use of JUnit 4 …

JUnit 4

Still in the Libraries tab and click Add Library, select JUnit and click Next. From the drop-down select JUnit 4 and click Finish. I prefer JUnit 4 to JUnit 3, it’s use of annotations simplifies developing tests.

Client Code

Now to write the test. We are going to invoke the service operation which retrieves the state of a Book Edition with a particular isbn

    http://localhost:9085/LibraryWink/library/editions/0863699936

And in our client we need a Java object that corresponds to the state returned. In the server code we already have a suitable Java Bean and so I simply copied that code into my Test (that’s just a temporary expedient, clearly it would be better to refactor shared code to a common library.)

The test code looks like this:

package org.djna.library.test;

import static org.junit.Assert.assertEquals;

import org.apache.wink.client.EntityType;
import org.apache.wink.client.Resource;
import org.apache.wink.client.RestClient;
import org.junit.Test;

public class EditionTester {
    @Test
    public void testExample() {
        RestClient libraryClient = new RestClient();
        String resoruceUri =
"http://localhost:9085/LibraryWink/library/editions/0863699936"
        Resource editionResource
                   = libraryClient.resource(resoruceUri);
        editionResource.header(
                   "Accept", "application/json"
                   );
        BookEdition edition = editionResource.get(
                      new EntityType<BookEdition>(){}
                     );
        assertEquals("0863699936", edition.getIsbn());
    }

}

There are a few points worth noting here. First concerning the JUnit tests:

  • import static org.junit.Assert.*; Java 5 enables static imports giving access to the various assertions that express the checks performed by the test.
  • The @Test annotation specifies that this method is a test. Hence I can request “Run As Junit” on this class and the method here will be executed.
  • The assertEquals() method checks that the edition retrieved from the service has the expected ISBN.
  • Some of the code here is standard “setup” code and when we have a few more test methods we’d refactor it into a setup method, which would be annotated with @Before.

Now to look at the Wink client code. This APIs used in this test code are worth studying, they could be useful in application code too. It’s clear that writing a client of a RESTful service is very easy.

  • RestClient libraryClient = new RestClient(); gives us client object to work with  …
  • and then we can use the client to specify a resource Resource editionResource = libraryClient.resource(resoruceUri);
  • Before invoking the method we need specify the MediaType that we can accept in the response. If you look at the service code you’ll see that the @Produces annotation specifies only JSON responses and by default this is not the requested type. So we have editionResource.header("Accept", "application/json" );
  • Finally we invoke the service, specifying the expected response Class: editionResource.get( new EntityType<BookEdition>(){} );

Conclusion

Creating JUnit tests for the RESTful service using the Wink client APIs is straight forward. There’s a few more test to write here, for example what happens if we specify a resource that does not exist? And I also need to test the edition creation POST operation. That’s for the next posting.

Advertisements

4 Responses to “Wink clients and Unit Testing JAX-RS Services”

  1. Oscar said

    Do you have some code using POST Method? (Sending JSON data). Tnx

    • djna said

      Hi Oscar, I’m not on my development machine right now, so I can’t test this but according to this the following should work:

      String response = resource.contentType(“text/plain”).accept(“text/plain”).post(String.class, “foo”);

  2. Abhijeet Gaikwad said

    Hi
    1. In post method call why is the second argument string(i am talking about “foo” as in above example).

    • djna said

      Hello Abhijeet. This is just an example of how to POST, taken from the Wink documentation. The second argument can be any Object, the example uses a String.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: