Using the Facade Pattern to More Easily Test static or Complex Classes

Featured image for sharing metadata for article

Something that came up recently with some cross-organisation colleagues is how to better test a complex interface, such as the AWS SDK in a unit test.

It's something I've come up against before, both with complex clients like AWS SDK's S3Client, but also with libraries like RestAssured or SLF4J's MDC. And each time, the Facade design pattern comes up as being a nice solution.

Let's say that we want to write a unit test to verify that the following API request is sent using Rest Assured:

import java.util.UUID;

import static io.restassured.RestAssured.given;

public class ApiClient {
  public Object doCall() {
    return RestAssured.given()
      .header("correlation-id", UUID.randomUUID().toString())
      .get("http://example.com/api");
  }
}

Unfortunately we'll notice that given() is a static method which we cannot test - at least without something evil like PowerMock, which we should really avoid where possible.

One of the easiest ways to solve this - which I use every time I start to work with Rest Assured - is to create a RequestSpecificationFactory, which is a facade around RestAssured's given method:

import static io.restassured.RestAssured.given;

import io.restassured.specification.RequestSpecification;

public class RequestSpecificationFactory {

  public RequestSpecification newRequestSpecification() {
    return given();
  }
}

There are other things we can do here, like be able to apply common configuration, or allow constructing the RequestSpecificationFactory with a set of Filters to apply to each method, but the key thing here is that we create a class that extracts the static calls, or calls that may require a lot of setup, or cannot be easily unit tested, and we make it injectable:

import java.util.UUID;

public class ApiClient {

  private final RequestSpecificationFactory factory;

  public ApiClient() {
    this(new RequestSpecificationFactory());
  }

  /*
    Test only, but could alternatively be for all use cases, and we require a
    <code>RequestSpecificationFactory</code> to be injected
  */
  ApiClient(RequestSpecificationFactory factory) {
    this.factory = factory;
  }

  public Object doCall() {
    return factory
        .newRequestSpecification()
        .header("correlation-id", UUID.randomUUID().toString())
        .get("http://example.com/api");
  }
}

Now we can provide this RequestSpecificationFactory instance to be injected via the constructor, allowing for easy unit testing, as well as giving us the ability to i.e. use the same instance of the RequestSpecificationFactory everywhere.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#java #testing.

This post was filed under articles.

This post is part of the series writing-better-tests.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.