WireMock Docker로 테스트

@WireMockTest 및 WireMockExtension을 사용하여 테스트에서 API를 조롱하는 데모를 보여주었습니다.

그러나 WireMock에는 official Docker image이 있습니다. 그것도 시도해 봅시다! 🤩




로저비나스 / 와이어목 테스트


🤹 WireMock 테스트




  • Docker Compose

  • App test with Testcontainers
  • Static stubs
  • Dynamic stubs

  • App run with Docker Compose

  • 도커 작성


    docker-compose.yml에서 다음 두 컨테이너를 구성합니다.

    version: "3.9"
    
    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
    


  • 동적 포트를 사용합니다.
  • 매개변수--global-response-templating를 추가하여 활성화response templating합니다(command line options 참조).
  • WireMock 매핑을 포함하는 디렉토리가 볼륨으로 마운트됩니다.

  • Testcontainers를 사용한 앱 테스트



    정적 스텁



    Testcontainers JUnit5 extension의 도움을 받아 먼저 이미 구성된 정적 스텁을 테스트합니다.

    @Testcontainers
    @TestInstance(PER_CLASS)
    class AppShouldWithWireMockDocker {
    
     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 = DockerComposeContainer<Nothing>(File("docker-compose.yml"))
       .apply {
        withLocalCompose(true)
        withExposedService(fooServiceName, fooServicePort, forListeningPort())
        withExposedService(barServiceName, barServicePort, forListeningPort())
        withLogConsumer()
       }
    
      @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()
      )
     }
    }
    


  • fooApiUrlbarApiUrl를 빌드하기 위해 각 컨테이너에 할당된 동적 포트를 얻습니다.

  • 동적 스텁



    또한 WireMock client을 사용하여 프로그래밍 방식으로 스텁을 구성하고 두 WireMock 컨테이너의 WireMock Admin API에 연결할 수 있습니다.

    @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", WireMock.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()
     )
    }
    


    Docker Compose로 실행되는 앱



    테스트에서 사용하는 것과 동일한 docker-compose를 쉽게 사용하여 애플리케이션을 시작하고 로컬에서 실행/디버그할 수 있습니다.



    이 경우 고정 포트를 사용해야 하지만 다음과 같이 docker-compose.override.yml를 사용하여 이를 달성할 수 있습니다.

    version: "3.9"
    
    services:
    
      foo-api:
        ports:
          - "8081:8080"
    
      bar-api:
        ports:
          - "8082:8080"
    


    이 재정의는 수동으로 실행docker compose할 때만 적용되며 편리하게 @Testcontainers에 영향을 미치지 않습니다.

    멋지지 않나요? 😎

    좋은 웹페이지 즐겨찾기