Integration testing with TestСontainers and JUnit 5

Integration testing with TestСontainers and JUnit 5

Fd8ac25831e3e9cc7d70944c77a369ef?s=128

Nikolay Kuznetsov

December 09, 2019
Tweet

Transcript

  1. Integration testing with TestСontainers and JUnit 5 Nikolay Kuznetsov @nikolayk812

    Helsinki JUG Zalando 9 December 2019
  2. About me • Go developer at Zalando Wardrobe • 6+

    years of Java experience • Conference speaker: ◦ Voxxed Days Cluj, Container Days Hamburg • TestContainers-Go contributor
  3. Why integration testing?

  4. 2 unit tests, 0 integration tests

  5. Basic integration test

  6. Trade-offs Test Runtime

  7. Integration testing evolution • In-memory mocking • Local DBs •

    Vagrant • Docker / Docker Compose • Docker API
  8. Docker advantages • 100% compatible database • Same version as

    production • Empty or known state
  9. Docker architecture

  10. How to start a container for test? • Shell scripts

    • Maven plugin • Docker Compose • Docker API • MiniKube, Kubernetes
  11. Shell scripts

  12. Maven plugins github.com/fabric8io/docker-maven-plugin

  13. Docker Compose

  14. Docker API docs.docker.com/engine/api/latest

  15. Exec example

  16. None
  17. TestContainers flavors

  18. TestContainers Java • github.com/testcontainers/testcontainers-java • Wraps docker-java library • Docker

    environment discovery • Host port randomization • Containers clean up on JVM shutdown • Readiness waiting strategies
  19. As simple as var redis = new GenericContainer("redis:5.0.6") .withExposedPorts(6379); var

    postgres = new PostgreSQLContainer();
  20. Docker environment discovery

  21. Talking to Docker via UDS • curl --unix-socket /var/run/docker.sock http:/localhost/containers/json

    • curl --unix-socket /var/run/docker.sock http:/localhost/networks
  22. Host port randomization • To prevent port conflicts • Enables

    parallel builds • API to get a host port
  23. Containers cleanup https://github.com/testcontainers/moby-ryuk

  24. Waiting strategies • Host port • HTTP • Log message

    • Docker healthcheck • Combined / Custom
  25. Host port waiting strategy • Default: at first exposed port

    with timeout of 60s • Both from outside and inside container
  26. Internal port check

  27. HTTP waiting strategy • Status & response body predicate

  28. Demo setup User Service

  29. Demo scenario User Service INSERT INTO SELECT FROM

  30. Demo github.com/nikolayk812/hjug-tc-demo

  31. Demo recap • JUnit 5 Extension API • TestContainer modules

  32. JUnit 5 extension points • Life-cycle callbacks • Conditional execution

    • Parameter resolution • Exception handling
  33. JUnit 5 extension logic • Implement interface(s) from o.j.j.api.extension package

    ◦ i.e. BeforeEachCallback, ExecutionCondition • Register with @ExtendsWith annotation • See @Testcontainers for reference
  34. TestContainers modules • Preconfigured, optimized for testing • Wrappers on

    top of GenericContainer class • 14 databases • MockServer, LocalStack, Kafka, ToxiProxy
  35. Demo-2: setup User Service

  36. Demo-2: Docker network User Service user-alias: 8083 postgres-alias: 5432 localhost:

    32812
  37. Demo-2: scenario User Service POST /users GET /user/<id>

  38. Demo-2 github.com/nikolayk812/hjug-tc-demo

  39. Demo-2: recap • Docker network and alias

  40. Why end-to-end testing? • Business flows across multiple services •

    Regression, when ◦ + new service ◦ - legacy service
  41. Some cluster Spring Cloud Kubernetes

  42. E2E strategies • Against a deployed cluster • Against on-demand

    in memory cluster
  43. Deployed cluster cons • Replace a service with a newer

    version => instability • Temporary service name => non-discoverable • Unexpected databases states ◦ Care to clear data after the test?
  44. On-demand cluster cons • Time to start all containers •

    Memory + CPU • How actually to create it?
  45. On-demand Kubernetes for E2E?

  46. YAGNI

  47. On-demand cluster TC approach • Each service started by TestContainers

    • Shared Docker network • Functional tests • Unless testing Kubernetes manifests
  48. E2E setup User Service Item Service

  49. Hints • Host port forwarding Testcontainers.exposeHostPorts() • Fixed host port

    (for remote debugging) GenericContainer.addFixedExposedPort() • Reusable containers github.com/testcontainers/testcontainers-java/issues/781
  50. Takeaways • https://testcontainers.org • Balance between flexibility, speed and features

    • Works on Mac, Linux, Windows • Great for integration tests! • Possible to use for end-to-end tests
  51. Thank you! @nikolayk812 nikolayk812 nikolayk812