Testing with WireMock Docker
Tags: wiremock, testcontainers, docker, tutorial
Published: 2022-01-25 23:48:40

In [Testing with @WireMockTest](https://dev.to/rogervinas/testing-with-wiremocktest-3da0) I showed a demo using **@WireMockTest** and **WireMockExtension** to mock APIs in our tests.

But **WireMock** has an [official Docker image](https://hub.docker.com/r/wiremock/wiremock), let's try that out too! 🤩

![Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lq53jy6ujyz4iwho7nw9.png)

{% github rogervinas/wiremock-testing no-readme %}

* [Docker Compose](#docker-compose)
* [App test with Compose Testcontainers module](#app-test-with-compose-testcontainers-module)
  * [Static stubs](#static-stubs)
  * [Dynamic stubs](#dynamic-stubs)
* [App run with Docker Compose](#app-run-with-docker-compose)

## Docker Compose

We configure these two containers in `docker-compose.yml`:

```yaml
services:

  foo-api:
    image: wiremock/wiremock:2.32.0
    ports:
      - "8080"
    command:
      - "--global-response-templating"
    volumes:
      - ./wiremock/foo-api:/home/wiremock

  bar-api:
    image: wiremock/wiremock:2.32.0
    ports:
      - "8080"
    command:
      - "--global-response-templating"
    volumes:
      - ./wiremock/bar-api:/home/wiremock
```

* We use dynamic ports.
* We enable [response templating](https://wiremock.org/docs/response-templating/) adding the parameter `--global-response-templating` (see [command line options](https://wiremock.org/docs/running-standalone/)).
* Directories containing **WireMock** mappings are mounted as volumes.

## App test with Compose Testcontainers module

### Static stubs

With a little help from [Testcontainers JUnit5 extension](https://www.testcontainers.org/test_framework_integration/junit_5/) we first test the static stubs already configured:

```kotlin
@Testcontainers
@TestInstance(PER_CLASS)
class AppShouldWithComposeTestcontainers {

 companion object {
  private const val name = "Ivy" 
  private const val fooServiceName = "foo-api"
  private const val fooServicePort = 8080
  private const val barServiceName = "bar-api"
  private const val barServicePort = 8080
  private lateinit var fooApiHost: String
  private var fooApiPort: Int = 0
  private lateinit var barApiHost: String
  private var barApiPort: Int = 0
   
  @Container
  @JvmStatic
  val container = ComposeContainer(File("docker-compose.yml"))
    .withLocalCompose(true)
    .withExposedService(fooServiceName, fooServicePort, forListeningPort())
    .withExposedService(barServiceName, barServicePort, forListeningPort())
   
  @BeforeAll
  @JvmStatic
  fun beforeAll() {
    fooApiHost = container.getServiceHost(fooServiceName, fooServicePort)
    fooApiPort = container.getServicePort(fooServiceName, fooServicePort)
    barApiHost = container.getServiceHost(barServiceName, barServicePort)
    barApiPort = container.getServicePort(barServiceName, barServicePort)
  }
 }

 @Test
 fun `call foo and bar`() {
  val fooApiUrl = "http://${fooApiHost}:${fooApiPort}"
  val barApiUrl = "http://${barApiHost}:${barApiPort}"

  val app = App(name, fooApiUrl, barApiUrl)

  assertThat(app.execute()).isEqualTo(
   """
    Hi! I am $name
    I called Foo and its response is Hello $name I am Foo!
    I called Bar and its response is Hello $name I am Bar!
    Bye!
   """.trimIndent()
  )
 }
}
```

* We obtain the dynamic ports that have been assigned to each container to build `fooApiUrl` and `barApiUrl`.

### Dynamic stubs

We can also configure our stubs programmatically using the [WireMock client](https://wiremock.org/docs/java-usage) and connecting it to the [WireMock Admin API](https://wiremock.org/docs/api/) of the two **WireMock** containers: 

```kotlin
@Test
fun `call foo an bar with dynamic stubs`() {
 val fooApiUrl = "http://${fooApiHost}:${fooApiPort}/dynamic"
 val barApiUrl = "http://${barApiHost}:${barApiPort}/dynamic"
  
 WireMock(fooApiHost, fooApiPort)
  .register(
   get(urlPathEqualTo("/dynamic/foo"))
    .withQueryParam("name", equalTo(name))
     .willReturn(ok().withBody("Hi $name I am Foo, how are you?"))
  )
 WireMock(barApiHost, barApiPort)
  .register(
   get(urlPathMatching("/dynamic/bar/$name"))
    .willReturn(ok().withBody("Hi $name I am Bar, nice to meet you!"))
  )
 
 val app = App(name, fooApiUrl, barApiUrl)
 assertThat(app.execute()).isEqualTo(
   """
     Hi! I am $name
     I called Foo and its response is Hi $name I am Foo, how are you?
     I called Bar and its response is Hi $name I am Bar, nice to meet you!
     Bye!
   """.trimIndent()
 )
}
```

## App run with Docker Compose

We can easily use the same **docker-compose** used by the test to start the application and run/debug it locally:

![Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7dv8qbjqst5nt8oyj3c1.png)

In this case we'll need to use fixed ports but we can achieve that with a `docker-compose.override.yml` like this:

```yaml
version: "3.9"

services:

  foo-api:
    ports:
      - "8081:8080"

  bar-api:
    ports:
      - "8082:8080"
```

This override is only applied when we execute `docker compose` manually and it conveniently does not affect **@Testcontainers**.

This is cool, isn't it? 😎