Insights

Easy API Simulation with Hoverfly JUnit Rule

By
Andrew Morgan
March 17, 2016
Share this post
https://opencredo.com/blog/easy-api-simulation-hoverfly-junit-rule
Copied!

In order to be able to regularly release an application, your automated tests must be set up to give you fast and reliable feedback loop. If bugs are only found during a long and expensive multi-service or end-to-end test run, it can be a hinderance to fast delivery. Unfortunately I have often seen this problem in development environments: a huge suite of clunky, flaky and slow end-to-end tests which test the full functionality of the application as opposed to being more lightweight and reflecting basic user journeys. This produces the "ice cream cone" anti-pattern of test coverage, where unit tests aren't providing the kind of coverage and feedback they need to.

This has been reposted from Spectolabs.

There are many reasons for this – developer laziness, a lack of understanding of a build’s importance by the business – or more technical issues such as the difficulties involved in stubbing the architectural boundaries of an application or service. You can’t know that everything works together until everything is deployed together.

Following on from the previous blog post, I’ve created a Hoverfly JUnit Rule which enables you to quickly and reliably simulate an external API in your Java unit / integration tests.

Hoverfly is a lightweight proxy which can be used to “capture” and “virtualize” (and thus simulate) external services. It also allows you to use custom middleware to modify requests and responses on demand, allowing for easier testing of resilience patterns in your environment. It’s written in Go, so it is fast and light on resource consumption, and because it is a proxy it is non-intrusive (meaning you don’t have to explicitly point to a stub webserver). As a single binary, it’s designed to be used in any stack across the whole test pipeline from unit testing to multi-service testing to end-to-end testing.

This JUnit rule wraps the Hoverfly binary and fits it into the Java unit testing tier, allowing for more reliable API simulation at the lowest level. The source code for the rule is available on GitHub.

Quick Start

The rule is available in Maven Central:

io.specto
hoverfly-junit
0.1.1


Hoverfly stores request-to-response mappings as json. This .json is either created by Hoverfly as it "captures" communication with an external service, or it can be created manually. The .json can be exported from and imported into Hoverfly.You can declare the rule as follows:

@Rule
public HoverflyRule hoverflyRule = HoverflyRule.buildFromClassPathResource("test-service.json").build();


The rule takes a convention over configuration approach, meaning this is all you need to do to get it working. Behind the scenes it will:

  1. Spin up and tear down Hoverfly before and after the rule.
  2. Load the .json into its database.
  3. Block until Hoverfly has started.
  4. Extract and execute the correct Hoverfly binary based on the underlying OS (The rule is not currently on a major release as there are likely to be edge cases in this area).
  5. Boot Hoverfly on unused ports to guarantee it won't clash with anything.
  6. Set the proxy host and port so any http requests from the Java client will go through Hoverfly.

An example test may look as follows:

public class HoverflyRuleTest {

    @ClassRule
    public static HoverflyRule hoverflyRule = HoverflyRule.buildFromClassPathResource("test-service.json").build();

    private RestTemplate restTemplate;

    @Before
    public void setUp() {
        restTemplate = new RestTemplate();
    }

    @Test
    public void shouldBeAbleToMakeABooking() throws URISyntaxException {
        // Given
        final RequestEntity bookFlightRequest = RequestEntity.post(new URI("http://www.my-test.com/api/bookings"))
            .contentType(APPLICATION_JSON)
            .body("{\"flightId\": \"1\"}");

        // When
        final ResponseEntity bookFlightResponse = restTemplate.exchange(bookFlightRequest, String.class);

        // Then
        assertThat(bookFlightResponse.getStatusCode()).isEqualTo(CREATED);
        assertThat(bookFlightResponse.getHeaders().getLocation()).isEqualTo(new URI("http://localhost/api/bookings/1"));
    }
}

(Please feel free to visit the project on GitHub if you wish to contribute!)

Hoverfly Java Exporter

What if when building a service, the pipeline also created a virtualized version of the service as an artefact? This could be handy for consumers who want to test against your service – simply give them the .json to import into Hoverfly and they can start testing. As somebody who has spent alot of time working with microservices I know this could have been beneficial in some of the CI pipelines I’ve worked with – run the tests, have the requests intercepted, produce a simulation, make it available to others. It would have saved alot of time spent stubbing services in the consumer tests. This approach tends to be quite error-prone – meaning you don’t encounter failures until deploying into an environment where there’s communication with the real service.

With these things in mind, I thought there would be value in producing Hoverfly .json from Java integration tests which may not use real http. MockMvc is a popular testing framework which only simulates http, so in order to get the requests intercepted, a servlet filter has been created which outputs them to a .json file. It can be found in Maven Central:

:

io.specto
hoverfly-jrecorder
0.1.1


Simply add the filter as an interceptor in your MockMvc test. It will output everything with the given base URL to the given path on the filesystem. This json can then be imported into Hoverfly for testing.

private static HoverflyFilter hoverflyFilter = new HoverflyFilter("www.my-test.com", "generated/hoverfly.json");

@Before
public void setUp() {
    this.mockMvc = webAppContextSetup(webApplicationContext)
        .addFilter(hoverflyFilter)
        .build();
}


This could fit very nicely into your CI pipeline, producing the virtualization on every build. The .json files could be uploaded to a repository such as Nexus, GitHub or some other location. The idea is that these files would be globally accessible, so the same test data could be used across the entire development stack. That’s one of the main advantages of Hoverfly: it’s possible for it to “fit” everywhere, therefore allowing you to re-use the service same behaviour across every tier of testing. Its also worth bearing in mind that if your tests use real http, you could use Hoverfly in “capture” mode to produce the .json as an alternative.

Please visit the project on GitHub if you wish to contribute.

In Conclusion

Hoverfly has value across all tiers of testing, from unit to end-to-end testing. Here we have focused primarily on Java Unit / Integration testing, but because data can easily imported into Hoverfly as .json it shows how interoperable it can be. It has also been demonstrated that service virtualization or “API simulation” could arguably be part of a build pipeline, allowing components to be tested easily by any number of consumers who use Hoverfly.

This blog is written exclusively by the OpenCredo team. We do not accept external contributions.

Share this post
Copied!
Software Consultancy
Andrew Morgan
Consultant at OpenCredo

Looking for a hands-on software delivery partner?

Book in a quick 20 minute chat with our consultants to explore your specific project and objectives.

OpenCredo-Graphic Illustration: Brainstorm
OpenCredo-Graphic Illustration: RocketShip