In Testing with @WireMockTest I showed a demo using @WireMockTest and WireMockExtension to mock APIs in our tests.
But WireMock has an official Docker image, let's try that out too! 🤩
rogervinas / wiremock-testing
🤹 WireMock Testing
Docker Compose
We configure these two containers in docker-compose.yml
:
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 adding the parameter
--global-response-templating
(see command line options). - Directories containing WireMock mappings are mounted as volumes.
App test with Compose Testcontainers module
Static stubs
With a little help from Testcontainers JUnit5 extension we first test the static stubs already configured:
@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
andbarApiUrl
.
Dynamic stubs
We can also configure our stubs programmatically using the WireMock client and connecting it to the WireMock Admin API of the two WireMock containers:
@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:
In this case we'll need to use fixed ports but we can achieve that with a docker-compose.override.yml
like this:
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? 😎
Top comments (0)