14 Testing beyond JUnit

 

This chapter covers

  • Integration testing with testcontainers
  • Specification-style testing with Spek and Kotlin
  • Property-based testing with Clojure

Last chapter we looked at the general principles which guide our testing. Now we’re going to dive deeper into specific approaches to improve our testing for different situations. Whether our goal is cleaner testing of dependencies, better communication in our testing code, or even discovery of edge cases we hadn’t considered, the JVM ecosystem provides many tools to help out, and we will highlight only a few.

Let’s start with that ever-present struggle - how to deal with external dependencies effectively when writing integration tests.

14.1 Integration testing with testcontainers

As we move up the pyramid from our isolated unit tests, we encounter a variety of obstacles. To integration test against a real database requires that we have a real database available to use! Getting the benefits of that realistic testing implies a huge increase in setup complexity. The statefulness of these external systems also increases the chances of our tests failing, not because of problems with our code, but because of unexpected state lingering between tests.

Over the years, this has been tackled in many ways, from in-memory databases to frameworks for running tests fully within transactions that clean up after themselves. But these solutions often bring their own edge cases and difficulties.

14.1.1 Installing testcontainers

14.1.2 An example with Redis

14.1.3 Gathering container logs

14.1.4 An example with Postgres

14.1.5 An example for end-to-end testing with Selenium

14.2 Specification-style testing with Spek and Kotlin

14.3 Property-based testing with Clojure

14.3.1 clojure.test

14.3.2 clojure.spec

14.3.3 test.check

14.3.4 clojure.spec + test.check

14.4 Summary

sitemap