Integration testing with TestСontainers-Go

Integration testing with TestСontainers-Go

GopherCon Europe 2020 - Lightning talk

Fd8ac25831e3e9cc7d70944c77a369ef?s=128

Nikolay Kuznetsov

June 18, 2020
Tweet

Transcript

  1. Integration testing with TestСontainers-Go Nikolay Kuznetsov GopherCon Europe 18 Jun

    2020 @nikolayk812
  2. 2 unit tests passed, 0 integration tests

  3. Basic integration test

  4. Getting a database for testing • Local database • In-memory

    mock • Docker!
  5. Docker advantages • 100% compatible databases • Same version as

    production • Empty DB state
  6. Integration testing with Docker

  7. Easy-peasy! docker run -d -p 5432:5432 postgres:12.1

  8. • Host port conflicts • Not ready сontainer / service

    • Resource leak (the container keeps running) • Stale data (if reusing the same container) What could go wrong?
  9. Solving some issues

  10. None
  11. Docker API docs.docker.com/engine/api/latest

  12. Exec example

  13. None
  14. TestContainers-Go github.com/testcontainers/testcontainers-go • Docker Go client under the hood •

    Host port randomization • Containers clean up at the test shutdown • Readiness waiting strategies
  15. As simple as pgContainer, err := tc.GenericContainer(ctx, tc.GenericContainerRequest{ ContainerRequest: tc.ContainerRequest{

    Image: "postgres:12.1", ExposedPorts: []string{"5432/tcp"}, }, })
  16. Host port randomization • API to get a host port:

    • Prevents port conflicts • Enables parallel builds port, err := pgContainer.MappedPort(ctx, "5432/tcp")
  17. Containers cleanup: Ryuk github.com/testcontainers/moby-ryuk • Ryuk kills containers (networks, volumes)

    by labels • TC assigns labels to started containers • TC keeps a connection to Ryuk open • Ryuk acts when the connection is terminated
  18. Waiting strategies • Host port • HTTP • SQL •

    Logs • Custom • Multi
  19. Host port waiting strategy • Impl checks both from outside

    and inside container • Default (customizable) timeout is 60 seconds tc.ContainerRequest{ Image: "postgres:12.1", ExposedPorts: []string{"5432/tcp"}, WaitingFor: wait.ForListeningPort("5432/tcp"), },
  20. HTTP waiting strategy WaitingFor: wait.ForHTTP("/health"). WithPort("8080/tcp"). WithStatusCodeMatcher( func(status int) bool

    { return status == http.StatusOK }),
  21. Takeaways • testcontainers.org • Balance between flexibility, speed and features

    • Great for integration tests • Possible to use for end-to-end tests
  22. Thank you! @nikolayk812 nikolayk812