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)