Tags

Unit Test JAX-RS using Java 6 and JUnit 4

Posted on by Nick. Posted in tutorial.

Today I was amazed to discover that Unit testing JAX-RS resources with JUnit 4 and Java 6 is insanely easy.

Have a look at the example below and then read the description underneath if things are not clear enough already.

import static org.junit.Assert.*;

import java.io.*;
import java.net.*;

import javax.ws.rs.*;

import org.junit.*;

import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.net.httpserver.HttpServer;

@Path("/hellotest")
public class MyResourceTest {

    private static final String LOCALHOST = "http://localhost:9998/";

    private static HttpServer server;

    @GET
    @Produces("text/plain")
    public String testSystem(){
        return "Hello. This is a test";
    }

    @BeforeClass
    public static void setUp() throws Exception{
        System.out.println("Creating server");
        server = HttpServerFactory.create(LOCALHOST);

        System.out.println("Starting server");
        server.start();

        System.out.println("HTTP server started");
        System.out.println("Running tests...");

        testResourceAtUrl(new URL(LOCALHOST + "hellotest"));
    }

    private static String testResourceAtUrl(URL url) throws Exception {

        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setRequestMethod("GET");
            connection.connect();

            InputStream inputStream = connection.getInputStream();

            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String firstLineOfText = reader.readLine();//you can also read the whole thing and then test
            System.out.println("Read: " + firstLineOfText);

            System.out.println("System was initialized correctly. About to run actual tests...");

            connection.disconnect();

            return firstLineOfText;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        throw new Exception("could not establish connection to " + url.toExternalForm());
    }

    @Test
    public void testMyMethod() throws Exception {
        String activationText = testResourceAtUrl(new URL(LOCALHOST + "myresource"));

        //TODO test here

    }

    /**
    * Destroy the server
    */
    @AfterClass
    public static void tearDown() throws IOException{
        System.out.println("Stopping server");
        server.stop(0);
        System.out.println("Server stopped");
    }

}

So here’s what the code above means:
1. @Path(“/hellotest”) The unit test itself is set up as a resource so when the tests are run we can check that the system is working by consuming the resource defined by testSystem()
2. Java 6 allows us to set up a HTTP server very easily using  HttpServerFactory.create(LOCALHOST) This way we simply go ahead and send HTTP requests without having to worry about 3rd party libs and setting up mock HTTP servers.
3. testResourceAtUrl(new URL(LOCALHOST + “hellotest”)) does the hard work: it requests the resource from the location that we specify in the method call.  
4. put your actual test data in the placeholder ;)

Of course this is a simplified test, and it is meant just to show you how easy it is to test your RESTful webservices. How would you make this better?

Cheers…

Tagged: , , ,

Comments (2 )

  1. Bruno Vernay on May 6, 2009 - 4:50 am

    Hi,
    Your post was very helpful !

    If you just want to get resources, you can use url.openStream() (see http://java.sun.com/docs/books/tutorial/networking/urls/readingURL.html)

    There are some problems if you try to run it with Eclipse:
    - You might see compile errors saying Access restriction: The type … is not accessible due to restriction on required library …
    The problem here is that the HTTP server used in that project is part of the Sun JRE6 but not part of standardized Java.
    Eclipse therefore blocks access to it.
    This can be fixed by going to the Window->Preferences window, selecting Java->Compiler->Errors/Warnings,
    selecting Deprecated and Restricted API and then changing the setting for Forbidden Reference and Discouraged Reference to Warning instead of Error.

    - Running it with the embedded maven gives an error: INFO: Scanning for root resource and provider classes in the paths:
    /usr/local/eclipse-3.4.2/plugins/org.maven.ide.components.maven_embedder_2.1.0.20080530-2300/jars/plexus-classworlds-1.2-alpha-12.jar
    May 5, 2009 6:41:42 PM com.sun.jersey.server.impl.application.WebApplicationImpl processRootResources
    SEVERE: The ResourceConfig instance does not contain any root resource classes.
    The solution is to configure an external Maven install.

    - Running it with JUnit in Eclipse works (doesn't) uses Maven.

    Bruno

  2. Nick on May 6, 2009 - 9:05 am

    Thanks Bruno! That’s helpful.