Proper integration tests require a complete setup of your infrastructure. And this can be a litle hard to put in place sometimes, especially when you need to support your developer lapop, your CI node, or any other machine where you need to run your tests. A good solution to fix this is to use containers as a common runtime. Docker works the same on every machine. So as long as it is installed on your developer laptop and your CI node, you are fine 🙂 So yet again I’ll show you how to do this using TestContainers.

What we want to test

There is a great sample app to test Couchbase with the Travel Sample. The Java backend is located here https://github.com/couchbaselabs/try-cb-java/ and the frontend here https://github.com/couchbaselabs/try-cb-frontend/. It will allow you to get an understanding of various features like N1QL, FTS or subdocuments. It’s a great place to start learning Couchbase. And while it’s a great place to learn, we still don’t have any integration tests for it. So I started out a new project to remedy that. It’s available on https://github.com/couchbaselabs/try-cb-integration-test. This is what I will write about today.

Test Setup

To test the frontend I am going to use Selenium. It allow you to basically specify where you want to click on a page, enter keystokes and verify the content of a page. So you can tell the selenium driver to load a page at a particular URL, verify that it’s correctly loaded, click on a link and verify that the new page brought you were you wanted. That’s all we are going to do today as far as testing go. The important thing here is how to setup this. First take a look at my Test code:

If you are familiar with Selenium, your eyes are probably hurting by looking at those big, long XPath values. In most application, this will be replaced by the id of the DOM element you are looking for. Now that we got this out of the way, take a look at the first line: RemoteWebDriver driver = chrome.getWebDriver();

The Selenium driver was given by a chrome objet. This object represents a Container running selenium. It’s possible thanks to TestContainers and their Selenium integration. But as it’s a container, to access something else, you either build it in the container or you have to link to another container. Which is of course what has been done. To run the Travel Sample you need three things. You need a Couchbase Server, a Travel Sample Backend and a Travel Sample Frontend, preferably all in their own container. Fortunately we have a Docker image for each of those. Please refer to the project Readme if you want to build them.

For all these to work, you need to start them in a particular order. First start Couchabse because it’s needed by the Backend. Than start the backend because it is needed by the frontend, than the Frontend because it’s needed by the Selenium image containing selenium and a browser. So we need to make sure each containers are started and ready before launching the other one. I say ready because it can be different than started in some cases. When you start a Couchbase Container, you then have to configure it. As for the Spring Boot application for the backend, it takes some time to be up and ready to accept connections. Fortunately TestContainers has thought about this and provides some interesting waiting mechanism.

Let’s start with the Couchbase Container:

You can see that it can be easily configured with this fluent API. Here I am setting this up so that it will have FTS, Index and Query services activated, that the travel sample will be preloaded, with my own username and passsword and with a default bucket as well.

Usualy with TestContainers you would have this has a @ClassRule in your tests. Which would start the container automatically. But it would start everything with a @ClassRule at the same time. Unfortunately we can’t do that because as explained earlier, containers need to be up and ready before starting the next one. So we can hack our way through this by adding a static block of code. They are all executed in order. So if we start our container in a start block, we can make sure they are up and ready before the next static block. The CouchbaseContainer Waiting strategy make polls on Couchbase’s REST API status and make sure the node state is healthy to consider it ready and stop waiting. If you want more details about CouchbaseContainer you can look at the code here and also on the previous blog posts about Couchbase and TestContainers.

Next step is to start the Java backend since Couchbase is up and ready:

Some interesing things to note here. Again the presence of a static block that starts the container for the same reasons stated previously. You can see we are exposing the port 8080 here. No need to do that with the CouchbaseContainer has it’s a specific class dedicated to the default Couchbase image. As such it has a default configuraion for ports as well as a predefined waiting strategy. For the backend we use a GenericContainer so we need to specify those. The waiting strategy will wait until getting a 404 for the configured path. If it answer something than basically the server is up and Frontend can use it. You will also see that the Java parameter defining Couchbase’s address is given and the value is fetched from the CouchbaseContainer instance.

Last bit of very useful information is the call to the withLinkToContainer method. It’s not part of the GenericContainer API, not sure why. I had to extend it:

All it does is make sure there will be a Docker link between the CouchbaseContainer and the backemd. This way you can make sure containers can talk to each others.

Now that Couchbase and the Backend are up and ready we can start the Frontend. It’s an Angular2 application inside the default nginx container. It needs to access the backend so we need to add a link to the previous container. Something you need to make sure is to be able to change the URL of the backend server dynamically in your Angular app. This can be done easily with Environments. This test image has been built with the test environments and as such look for the trycbBack hostname, which is the name give in the withLinkToContainer method. And again we start the container in a static block.

Once all thoses containers are up and running we can start the Selenium container. This one is part of the TestContainers project and gives you access to several feature. You can decide if you want to use Chrome or Firefox and if you want the test to be recorded. In our case it’s a chrome driver and the test will be recored and stored in the target fodler. You will also notice that we add a link to both the Frontend and Backend. The Frontend is accessed in the Chrome brower inside the container, and the angular app will access to the backend from it. So you need to make sure that it’s accessible as well from the Selenium container and that your CORS configuration will allow communication.

Now you have everything setup and you can run the test presented at the beginning of this post. Hope this was useful and that you will now use TestContainers for easy integration test of Couchbase based applications.

Posted by Laurent Doguin, Developer Advocate, Couchbase

Laurent is a Paris based Developer Advocate where he focuses on helping Java developers and the French community. He writes code in Java and blog posts in Markdown. Prior to joining Couchbase he was Nuxeo’s community liaison where he devoted his time and expertise to helping the entire Nuxeo Community become more active and efficient.

Leave a reply