Functional testing Java-EE applications with TestEE.fi – Part 5: JAX-RS and REST resources

A common pattern to communicate with backend systems today are RESTful HTTP resources, usually using JSON as the payload format. The standard for exposing your application’s functionality in a Java-EE application as REST resources is JAX-RS.

TestEE.fi allows you to test your application including your REST resources by combining the awesome and speedy Jetty servlet container with the JAX-RS reference implementation Jersey and integrating it seamlessly with the features you’ve already made yourself acquainted with in the previous installments.

Testing REST resources

In the previous parts of this series of articles we’ve covered the topics of mocking certain beans (adapters to external systems for example) during test execution in part 2 and had a deep dive into testing with JDBC and JPA in part 3.

Our approach in these examples was to have some bean (usually at the facade layer) injected in the test case and testing the business logic using method calls. While this approach allows for decent functional testing of your application’s business and persistence code, the presentation layer (i.e. your REST resources) is mostly out of reach.

While injecting the JAX-RS compliant REST resources into your test class is possible with TestEE.fi, you’d still be missing out much if the presentation logic that JAX-RS orchestrates at runtime, such as:

…to only name a few of the very handy extensions JAX-RS allows for. Being able to include these features in your automated tests in order to see if your REST resources will work in production can be a huge benefit – even more so when you don’t have to start up your application container for it.

Using TestEE.fi’s REST extension

TestEE.fi doesn’t include the REST extension in the *-all depedencies (testeefi-junit4-all, testeefi-junit5-all, testeefi-cucumber-all) since Jersey and Jetty add some amount of classes to your test runtime classpath which can slow down test execution. So be sure to only include it in projects where you actually want to test your REST resources.

In order to have the REST testing extension available in your tests you need to add the testeefi-rest dependency.

In Maven a minimal setup looks like this:

<dependencies>
    <!-- Base dependency for JUnit 4 based testing -->
    <dependency>
        <groupId>fi.testee</groupId>
        <artifactId>testeefi-junit4-all</artifactId>
        <version>0.6.1</version>
        <scope>test</scope>
    </dependency>
	
    <!-- Extension for REST testing -->
    <dependency>
        <groupId>fi.testee</groupId>
        <artifactId>testeefi-rest</artifactId>
        <version>0.6.1</version>
        <scope>test</scope>
    </dependency>
	
    <!-- Logging implenentation - TestEE.fi uses slf4j -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.7</version>
        <scope>test</scope>
    </dependency>
</dependencies>
TestEE.fi REST extension - Maven setup

In Gradle your dependency setup would look like this:

dependencies {
	testCompile 'fi.testee:testeefi-junit4-all:0.6.1'
	testCompile 'fi.testee:testeefi-rest:0.6.1'
	testCompile 'ch.qos.logback:logback-classic:1.1.7'
}
TestEE.fi REST extension - Gradle setup

Once you have TestEE.fi’s REST extension in your test classpath, an interface called “RestServer” becomes available for @Resource injection in your test classes – it’s only purpose is to provide you with the HTTP port your test server is listening on and its declaration looks as follows:

public interface RestServer {
    int getPort();
}
TestEE.fi's RestServer interface

The method getPort() returns a (randomly chosen) per-test-method port where Jetty listens and forwards all HTTP requests in the “/rest” context to Jersey.

Writing your first REST test with TestEE.fi

Since we will be testing HTTP REST resources we’re in need for a simple HTTP client to use in our test methods. I’ll be using the slim and simple okhttp library. You can of course use the HTTP client library of your choice, or even go for a HTTP client specifically designed for automated testing of REST interfaces, such as REST-Assured. I’ll also be using org.json in order to compose and parse JSON messages in my test code. For the sake of simplicity of this example, the REST resource we’ll be testing simply bounces back a JSON wrapped value we POST to it.

@RunWith(TestEEfi.class)
public class MyResourceTest {
    private final OkHttpClient client = new OkHttpClient();

    @Resource
    private RestServer restServer;

    @Test
    public void returns_request() throws IOException {
        // Prepare the request body
        final JSONObject requestBody = new JSONObject();
        requestBody.put("value", "Hello world");

        // Get the port at which our test server is running
        final int port = restServer.getPort();
        final okhttp3.Request request = new okhttp3.Request.Builder()
                .post(RequestBody.create(MediaType.parse("application/json"), requestBody.toString()))
                .url("http://localhost:" + port + "/rest/example/resource")
                .build();

        // Assert the response
        final Response response = client.newCall(request).execute();
        try (final ResponseBody body = response.body()) {
            final String string = body.string();
            assertEquals("Wrong response code. Body: " + string, 200, response.code());
            assertEquals("Hello world", new JSONObject(string).get("value"));
        }
    }
}
REST testing with TestEE.fi

Since this is quite some amount of code at once let’s just digest is piece by piece.

  • Line 1: Run your test with TestEE.fi
  • Lines 5-6: The RestServer is injected into the test case as a @Resource
  • Line 15: The port  where the REST server is running is returned by RestServer.getPort()
  • Line 18: Let’s have a closer look at how the URL is composed
    • “http://localhost” is obvious – we’re running the test on your machine
    • The port number returned from restServer is used
    • The context root in TestEE.fi for REST resources is always “/rest”
    • I’m using the REST application path “/example” (as can be seen in the sample code here)
    • The name of the REST resource is “/resource” (as can be seen in the sample code here)

As you can see, TestEE.fi’s REST extension works exactly as your application container of choice would. The JAX-RS applications and resources are discovered automatically and exposed via HTTP at a port you can retrieve using the @Resource injected RestServer interface.

Be sure to have a look at the source code of the sample application from which the above test class was taken. The source code can be found here.

Conclusion

While testing your application’s functionality starting at the facade layer using method calls is a practical and recommended approach, it might be rewarding to instead include the REST resources in your automated tests, as well. TestEE.fi makes it easy to expose your application’s REST resources in a test case without the need to start an application container.

If you want to know more about advanced testing with TestEE.fi, be sure to check out the other posts of this series to get you up to speed quickly:

Leave a Reply

Your email address will not be published. Required fields are marked *