Wiremock http://wiremock.org/, is a great tool to mock out real REST service dependencies to improve your integration testing without  needing the full interdependent system in place.

In this specific example we look at how to very easily mock a REST call returning a PDF file using the execute method of the Spring Rest Template and basic wiremock constructs.

Code

The code will be written using spring boot and gradle.

Dependencies

plugins {
    id 'application'
    id 'org.springframework.boot' version '2.3.2.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
}

mainClassName="org.example.wiremock.PDFClient"

group 'org.example'
version '1.0-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web:2.3.2.RELEASE'
    testImplementation 'org.springframework.boot:spring-boot-starter-test:2.3.2.RELEASE'
    testImplementation 'com.github.tomakehurst:wiremock-jre8:2.27.0'
    testCompile  'junit:junit:4.12'
}

Application

package org.example.wiremock;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.*;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;

@SpringBootApplication
@RestController
public class PDFClient {

    public static void main(String[] args) {
        SpringApplication.run(PDFClient.class, args);
    }

    public static String TARGET_HOST = "http://www.yesterdaysclassics.com";
    public static String TARGET_PATH = "/previews/burt_poems_preview.pdf";

    @GetMapping(value = "/pdf", consumes = "application/json")
    public ResponseEntity<byte[]> eg() {

        RestTemplate template = new RestTemplate();
        template.getMessageConverters().add(new ByteArrayHttpMessageConverter());

        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM));
        HttpEntity<String> entity = new HttpEntity<String>(headers);

        ResponseEntity<byte[]> response = template.exchange(TARGET_HOST + TARGET_PATH, HttpMethod.GET, entity, byte[].class);

        headers.setContentType(MediaType.parseMediaType("application/pdf"));
        headers.add("content-disposition", "inline;filename=eg.pdf");
        headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        return response;

    }
}

The application makes a rest call to an external site to display a pdf.

Test

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class PDFClientTest {

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(80);

    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate template;

    @Test
    public void pdfIsReturned() throws Exception {

        String expectedPdf = "a poem";

        TARGET_HOST = "http://localhost";

        wireMockRule.stubFor(any(urlPathMatching(TARGET_PATH))
          .willReturn(aResponse().withStatus(200).withBody(expectedPdf.getBytes())));

        String url = "http://localhost:" + port + "/pdf";
        String actualPdf = template.execute(new URI(url), HttpMethod.GET, requestCallback(), extract());

        assertEquals(expectedPdf, actualPdf);

    }

    private RequestCallback requestCallback() {
        return clientHttpRequest -> {
            clientHttpRequest.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/json");
        };
    }

    private ResponseExtractor<String> extract() {
        return resp ->  new String(ByteStreams.toByteArray(resp.getBody()));
    }
}

We replace the target host with local host as the embedded wiremock server will run on localhost of course. We set the stub for wiremock to match the path and the mocked response. The interesting part is the template execute callbacks 'requestCallback' and 'extract'.

These callbacks give us the flexibility using Springs TestRestTemplate to set up the request, perhaps if needed map JSON objects more finely like so:

 ObjectMapper mapper = new ObjectMapper();
            mapper.writeValue(clientHttpRequest.getBody(), somevalue);

In our case we just need to set the header.

The response callback gives us the ability to handle the resulting byte stream and simply convert it to string.

Notice how the wiremock part is only a couple of lines.

Full Source Code

This can be found here:

https://gitlab.com/lightphos/spring/wiremockpdf-tut/-/tree/master