<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Sbt on Adam J King</title><link>https://comforting-babka-f6ed67.netlify.app/tags/sbt/</link><description>Recent content in Sbt on Adam J King</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Wed, 06 Sep 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://comforting-babka-f6ed67.netlify.app/tags/sbt/index.xml" rel="self" type="application/rss+xml"/><item><title>Turning Docker Compositions into Test Suites</title><link>https://comforting-babka-f6ed67.netlify.app/p/turning-docker-compositions-into-test-suites/</link><pubDate>Wed, 06 Sep 2023 00:00:00 +0000</pubDate><guid>https://comforting-babka-f6ed67.netlify.app/p/turning-docker-compositions-into-test-suites/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Use Docker compositions in tests with Test-Containers and ScalaTest.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/AdamJKing/blackbox-testing-sample" target="_blank" rel="noopener"
&gt;Sample code repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;docker-compose&lt;/code&gt; as a tool that can build, deploy, and manage multiple containers on the same
network. These configurations, known as compositions, remove a lot of the manual setup we often associate with running
infrastructure locally. It provides local versions of dependencies for a faster, more realistic
feedback loop when developing applications.&lt;/p&gt;
&lt;p&gt;Our application level tests could look as simple as this;&lt;/p&gt;
&lt;script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2FAdamJKing%2Fblackbox-testing-sample%2Fblob%2Feed9b2a6bef9fa2049c9be1908415ee43c3a9347%2Fintegration-tests%2Fsrc%2Ftest%2Fscala%2Fblackbox%2Ftesting%2Fsample%2FAppSpec.scala%23L19-L34&amp;style=a11y-light&amp;type=code&amp;showBorder=on&amp;showLineNumbers=on&amp;showFileMeta=on&amp;showFullPath=on&amp;showCopy=on"&gt;&lt;/script&gt;
&lt;h3 id="test-containers"&gt;Test Containers
&lt;/h3&gt;&lt;p&gt;For our tests we will use &lt;a class="link" href="https://github.com/testcontainers/testcontainers-scala" target="_blank" rel="noopener"
&gt;test-containers&lt;/a&gt;. It offers us;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access to a Docker context from within tests.&lt;/li&gt;
&lt;li&gt;Integration with test harnesses provided by popular testing frameworks.&lt;/li&gt;
&lt;li&gt;The automatic creation and clean-up of Docker containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Test-Containers&lt;/code&gt; has a &lt;code&gt;Docker-Compose&lt;/code&gt; plugin that allows us to run compositions from our tests. First, let’s define a
simple composition file.&lt;/p&gt;
&lt;script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2FAdamJKing%2Fblackbox-testing-sample%2Fblob%2Feed9b2a6bef9fa2049c9be1908415ee43c3a9347%2Fdocker-compose.yaml&amp;style=a11y-light&amp;type=code&amp;showBorder=on&amp;showLineNumbers=on&amp;showFileMeta=on&amp;showFullPath=on&amp;showCopy=on"&gt;&lt;/script&gt;
&lt;p&gt;I’ve kept it simple by only including our application, but from this point on I can extend it with whatever setup we
need without having to change our tests at all. To start using this in our tests we’ll need to do three things.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build and publish our application image locally.&lt;/li&gt;
&lt;li&gt;Integrate our composition setup into our test-suite.&lt;/li&gt;
&lt;li&gt;Create a client that can call our application.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="1-build-and-publish-our-application-image-locally"&gt;1. Build and publish our application image locally.
&lt;/h3&gt;&lt;p&gt;Before we can use it in a test suite we need to build our application into a Docker image. Unfortunately
&lt;code&gt;Docker-Compose&lt;/code&gt; does not have a concept of running external build tasks to get an image. That said most build tools
will
allow us to build an image before running our test suite. With SBT
and &lt;a class="link" href="https://www.scala-sbt.org/sbt-native-packager/" target="_blank" rel="noopener"
&gt;native-packager&lt;/a&gt; plugin makes it easy to add our Docker build stage
as a prerequisite for our integration tests.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An SBT quirk means we need to specify our Docker build step for every test task.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Test / test := (Test / test).dependsOn(server / Docker / publishLocal).value,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Test / testOnly := (Test / testOnly).dependsOn(server / Docker / publishLocal).evaluated,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Test / testQuick := (Test / testQuick).dependsOn(server / Docker / publishLocal).evaluated
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="2-integrate-our-composition-setup-into-our-test-suite"&gt;2. Integrate our composition setup into our test-suite.
&lt;/h3&gt;&lt;p&gt;Next, we add the image details to our tests.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Test-Containers&lt;/code&gt; library has integrations for many test frameworks, which makes this easier, but we’ll still need
to do some wiring. The &lt;code&gt;Docker-Compose&lt;/code&gt; module needs to know the location of our compose-file. You might want to
hard-code this but that affects the portability of your tests. Instead, I recommend passing the location in as a
property and using SBT to locate the file. This has the benefits us by enabling testing against multiple compose-files;
useful for testing against different environments or setups.&lt;/p&gt;
&lt;script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2FAdamJKing%2Fblackbox-testing-sample%2Fblob%2F388fe4e99956353c83e99f38f60a1c90f903c3fc%2Fbuild.sbt%23L39&amp;style=a11y-light&amp;type=code&amp;showBorder=on&amp;showLineNumbers=on&amp;showFileMeta=on&amp;showFullPath=on&amp;showCopy=on"&gt;&lt;/script&gt;
&lt;p&gt;If you use an IDE to run test-suites you may need to update the runner config before this will work. In IntelliJ, you
can save a run configuration and share it by committing it to the repo.&lt;/p&gt;
&lt;p&gt;We need to wait for our containers to start before using them. We can get around this by making our access details lazy
or use the Test-Containers helpers (which run after the containers finish starting).&lt;/p&gt;
&lt;script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2FAdamJKing%2Fblackbox-testing-sample%2Fblob%2Fmain%2Fintegration-tests%2Fsrc%2Ftest%2Fscala%2Fblackbox%2Ftesting%2Fsample%2FAppFixture.scala%23L34-L36&amp;style=a11y-light&amp;type=code&amp;showBorder=on&amp;showLineNumbers=on&amp;showFileMeta=on&amp;showFullPath=on&amp;showCopy=on"&gt;&lt;/script&gt;
&lt;p&gt;Lastly we need to instruct Test-Containers on how to use our containers.&lt;/p&gt;
&lt;script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2FAdamJKing%2Fblackbox-testing-sample%2Fblob%2Fabed609fdbe0c4a17dfedebf7005bbc89eead893%2Fintegration-tests%2Fsrc%2Ftest%2Fscala%2Fblackbox%2Ftesting%2Fsample%2FAppFixture.scala%23L39-L47&amp;style=a11y-light&amp;type=code&amp;showBorder=on&amp;showLineNumbers=on&amp;showFileMeta=on&amp;showFullPath=on&amp;showCopy=on"&gt;&lt;/script&gt;
&lt;p&gt;Some additional considerations you might make;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We added a wait condition for the service’s health-check so that &lt;code&gt;Test-Containers&lt;/code&gt; knows to start testing. For more
complex start conditions check out
the &lt;a class="link" href="https://java.testcontainers.org/features/startup_and_waits/#:~:text=not%20a%20daemon.-,Wait%20Strategies,container%20is%20ready%20for%20use" target="_blank" rel="noopener"
&gt;test-containers documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We only listen to logs of the main container as logging everything at once creates too much noise. To help with that
we can either:
&lt;ul&gt;
&lt;li&gt;Set noisy application’s log-levels through the Docker environment.&lt;/li&gt;
&lt;li&gt;Use Test-Containers logging classes to build something custom.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-create-a-client-to-call-our-application"&gt;3. Create a client to call our application.
&lt;/h3&gt;&lt;p&gt;Finally let’s create our HTTP client to call our service. We have full access to the Docker containers and, if needed,
we can connect to our dependencies directly. Alternatively if you provide clients for your service you can use them
here instead.&lt;/p&gt;
&lt;script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2FAdamJKing%2Fblackbox-testing-sample%2Fblob%2Fabed609fdbe0c4a17dfedebf7005bbc89eead893%2Fintegration-tests%2Fsrc%2Ftest%2Fscala%2Fblackbox%2Ftesting%2Fsample%2FAppClient.scala%23L12-L24&amp;style=a11y-light&amp;type=code&amp;showBorder=on&amp;showLineNumbers=on&amp;showFileMeta=on&amp;showFullPath=on&amp;showCopy=on"&gt;&lt;/script&gt;
&lt;h2 id="summary"&gt;Summary
&lt;/h2&gt;&lt;p&gt;With our test fixture code in place we can now start writing code without too much concern about the state of our
containers.&lt;/p&gt;
&lt;script src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2FAdamJKing%2Fblackbox-testing-sample%2Fblob%2Feed9b2a6bef9fa2049c9be1908415ee43c3a9347%2Fintegration-tests%2Fsrc%2Ftest%2Fscala%2Fblackbox%2Ftesting%2Fsample%2FAppSpec.scala%23L19-L34&amp;style=a11y-light&amp;type=code&amp;showBorder=on&amp;showLineNumbers=on&amp;showFileMeta=on&amp;showFullPath=on&amp;showCopy=on"&gt;&lt;/script&gt;
&lt;p&gt;Now if we hit a test failure we can launch our &lt;code&gt;docker-composition&lt;/code&gt; to debug our test case. This helps us switch to an
iterative, live feedback loop for manual testing and experimentation.&lt;/p&gt;</description></item></channel></rss>