This library offers traits that developers can mix into their scala tests, which:
- Spin up preconfigured services in docker containers alongside your test
- Right now that's just localstack and redis, but we hope for many others to be added.
- Or you can quickly configure your own! - The docker heavy lifting is provided by the excellent docker-it-scala project.
- Offer complementing matchers for each container trait which offers fluent-style matching, keeping tests readable and reducing boilerplate further.
- Offer utility classes which provide some basic operations for the related service, facilitating pre-test setup.
Add the test dependency.
❌ This project is not currently being published. For now, you'll have to publish locally using sbt publishLocal
, sorry! 😬
Add the dependency to your build:
libraryDependencies += "com.hbc" %% "docker-it" % "0.9.12" % Test
Add the DockerSuite
trait to your test, then add one or more *Container
traits for each container you wish to run.
E.g., to run a suite with both Redis and Localstack, your suite should be similar to:
class MyTestSuite extends WordSpec
with DockerSuite with RedisContainer with LocalStackContainer {
...
}
When your test starts, the redis container and localstack containers will start, and will be killed after the test runs.
Some points:
- The test will not begin until all containers are ready, i.e. the services that the containers
offer have been confirmed started.
- In the case of the LocalStack container, that can be ~15 seconds!
- If you don't have the relevant docker images cached, docker will have to fetch them, resulting in a much longer first-run.
- The containers map the known service ports to ephemeral ports. That way, if a test JVM is aborted or some other critical error leaves a container behind alive, subsequent runs won't fail with in-use ports.
As new traits and util methods get implemented, we'll add coverage to DockerSuiteTest, so if you just want to see (copy and paste) an example, it's a good starting point.
Brings in:
redisPort:Int
: the ephemeral port mapped to the redis service. Pass this to your production code under test.redis:com.twitter.finagle.redis.Client
into scope, the twitter/finagle client configured to communicate with the service.- Use this in your test to do any test data prep (use
RedisUtil(redis)
for some common convenience methods)
- Use this in your test to do any test data prep (use
- Some fluent matchers on the
redis
client:
// redis should only contain these keys
redis should haveOnlyKeys("one", "two")
// other keys may exist
redis should haveKeys("human", "dog")
// keys should exist that match the pattern
redis should haveKeysMatching("*o*")
// redis "get dog" should return "woof"
redis should haveValueOnGet("dog", "woof")
// redis "get user" should result in the circe encoded JSON for User("Homer","Simpson")
redis should haveEncodedValueOnGet("user", User("Homer","Simpson"))
The LocalStack container offers many services, but right now we're only starting with Kinesis (Feel free to contribute!). This trait introduces:
portWebUI:Int
: the ephemeral port mapped to localstack's web UIportKinesis:Int
: same, but for the Kinesis serviceportCloudwatch:Int
: same, but for the CloudWatch servicedummyAWSCreds:AWSCredentialsProvider
: LocalStack doesn't need credentials, but the AWS clients do, so you can pass this in when building your clients.
The LocalstackContainer
trait brings in the KinesisMatchers
trait, which introduces:
kinesis:AmazonKinesis
: an AWS Kinesis client, configured to talk to localstack's service. Pass this to your production code (or use for your own test setup).- Use
KinesisUtil(kinesis)
for some common convenience methods)
- Use
- Some fluent matchers on the
kinesis
client:
// the kinesis stream should contain the following (circe JSON encoded) payloads
kinesis should havePendingEvents("mystream", Seq(User("Homer", "Simpson"), User("Moe","Szyslak")))
The LocalstackContainer
trait brings in the CloudWatchMatchers
trait, which introduces:
cloudwatch:AmazonCloudWatch
: an AWS cloudwatch client, configured to talk to localstack's cloudwatch service.
TODO(barry): This trait is a WIP. Localstack provides support for Cloudwatch under the hood with moto (the mocking lib for AWS's boto client), which appears to be rather limited right now. Much trial and error.
- Problem: I see the following error almost immediately after starting my test.
Solution: Your code is trying to interact with the container before it is ready. Don't use any of the utils or any of the clients (that the traits bring into scope) outside of your tests, i.e. before the
[info] A timeout occurred waiting for a future to complete. Queried 11 times, sleeping 15 milliseconds between each query. (LocalstackContainer.scala:27)
beforeAll()
is complete. Any references outside the tests should belazy
. If you've implemented abeforeAll()
, don't forget to make asuper.beforeAll()
call.