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
fooApiUrlandbarApiUrl.
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)