Creating Web Integration Tests for Spring Boot REST Controller

I’ve been working on a simple REST API for a CRUD backend application using Spring Boot. Nothing revolutionary, but it’s simply a new way of writing less code that I haven’t tried before.

Spring Boot is part of the Spring web application framework. The beauty of the Spring Boot project lies in using convention over configuration (similar to Ruby on Rails) to speed up development of web applications. It’s fast to run, you don’t need to worry about containers since the application has Tomcat embedded, and you can write a REST API in just a few lines of code with minimal configuration.

In this article, I will not go in depth into how to configure a Spring Boot application from the beginning. I will focus on creating a Controller class that will expose a REST API and how to write web integration tests to make sure it’s working as intended. I’ll be using Spring Boot version 2.0.1.

Controller Class

In my simple application, I’m just making a CRUD interface for a Fabric object. I want to expose five methods to start: listing all fabrics, creating a new fabric, retrieving a specific fabric, updating a specific fabric and deleting a specific fabric.

In Spring Boot you can create a REST Controller class by using the @RestController annotation. I also added the @RequestMapping annotation to give a prefix of “api/v1/” to all actions which I’m mapping on each method.

The next thing to do is to create our interface to a JpaRepository and use the @AutoWired annotation to inject our dependency via the constructor. 

The repository will be responsible for allowing access to the data source. To keep this post short I’ll not show how to create a data source but you can read more about it here.

Now that we can access data the first action to map is a way to list all fabrics in the database. We can do this by simply calling the findAll() method on the repository. Notice the @RequestMapping annotation to specify the request method and the last part of the URL. We’ll follow this pattern for all methods.

We can create a new Fabric object by doing a POST to the same endpoint. The method will return the object.

To get a specific object we access it by ID.

To update a specific object we retrieve it and then copy the properties of the passed in object to the retrieved one.

Finally, we also want to be able to delete a specific object. 

This concludes our Controller class and our five methods. As you can see we can implement a very simple CRUD API in just over 30 lines of code.

Web Integration Test Class

Now I want to make sure that the API is working as intended. In order to do that I can write some web integration tests.

The first thing to do is to create my class.

We use the @RunWith annotation to specify that we’ll be running this class with the Spring JUnit class runner. The @SpringBootTest explicitly sets this a test class for our application. Finally, the @DirtiesContext forces our tests to run with a clean database each time so that we don’t have to clean it ourselves.

As seen before, we can use the @Autowired annotation to inject objects. In this case, we can inject a TestRestTemplate which will allow us to make calls to our API. 

We’re also setting a few private variables that will be used in all test methods when creating a Fabric object.

Our first test is to make sure that, on an empty database, we retrieve an empty list of objects. Notice the @Test annotation to mark this method as a runnable test. We can call the getForEntity method on our TestRestTemplate object and then inspect the ResponseEntity object to make sure the Status Code is set to 200 and that the list is indeed empty.

In order to test if we can create a new object, we’ll follow a similar pattern. We create the object, pass it in our request, which this time is using the POST method, and then inspect the response to see if all our parameters are the same. Remember, our API methods always retrieve an object.

To test retrieving a specific object we’ll start by creating one and then finding it. We could have used mocking in this test but I wanted to keep these tests mock free so that the real API was always used.

Now we want to test if we can update an existing object. We’ll have to create it first, before calling our update method.

Finally, we’ll test if we can delete an existing object. 

So there you have. We’ve implemented and tested a simple CRUD interface using Spring Boot. 

United Colours of File Systems

The Problem

This weekend I needed to access some external hard drive folders on a Windows laptop. We follow a united colours approach to our systems at home, which, just like in the real world comes with a big set of advantages and occasional challenges. One of the downsides is the fact that each operating system uses different file systems.

This hard drive, in particular, had folders that had been created in an Ubuntu Linux laptop and some that have been created in a macOS laptop. They needed to be read on a Windows 10 laptop. Should this be easy? The honest answer in my experience? Most of the times, but not always…which can be abbreviated as sometimes!

Now, I’m not going to comment on Apple’s reluctance in accepting different colours and flavours of file systems and tools than their own but this is usually the biggest challenge. Over the years I found that Windows and Ubuntu play nicely with each other than macOS. Not this time though.

I mounted my hard drive on Windows and could see all my folders. but when accessing them I was confronted with two different types of issues.

Some folders were complaining that I didn’t have permission to access them. I matched all of these as folders that were created in macOS. This was a non-issue as I just had to give myself permission to access them by confirming the popup dialogue, just like in the image below.

Permission to continue for macOS file system folders
Make sure you just give yourself permission to access the folder

With the rest of the folders, I had a different issue though.

Location not available for Linux file system folders
Location not available

My folder was not available. The suggestions weren’t very helpful either. I searched online for a solution but most of them were pretty heavy-handed and involved formatting my file system, which could lead to losing my data.

The Solution

I did some online research on differences between HFS, NTFS and ext4. I already knew some things, others didn’t and yet I couldn’t find a solution that matched my case. And then, just as a lightbulb going up (or any other analogy for a Eureka moment) I remembered an almost insignificant and superficial detail.

Some of my folders were accessible after giving my user permission. Not only these folders were created on macOS but they also didn’t have one particular character in their names, “:“. Windows systems don’t allow the use of colon characters due to them serve as a drive separator, such as in “C:”. In macOS, because it’s a Unix based system you can technically use a colon in filenames but not through Finder. Finder doesn’t allow you to do this due to historical reasons.  I know most people use Finder to create folders since it’s the easiest way to drag and drop files. These folders didn’t have any colon characters because we can’t save them with them! The solution was apparent.

I plugged in my hard drive in my Linux laptop, promptly got rid of the colon characters and lo and behold it now didn’t complain at all in Windows!

I felt this was one of those moments where the solution was staring you in the face and yet you couldn’t see it for it was so simple that it just couldn’t be that. 

Hopefully, this will help anyone with the same corner-case that I faced!