TDD — URL Shortening Service: Part 1

A complete implementation of TinyURL using Spring Boot and Deploy the live service on cloud.

Introduction:

Many of you already know this is a very popular System design question asked by big companies to test their interview candidates. The reason why this problem is so famous is, because there are many different approaches you can take and the bottlenecks that you can encounter are different based on the situations. So, the interviewer will drive you to go that way and try to test you.

There are already a lot of articles that you can find on internet that will explain you the system design. The best explanation I found is by Narendra L who has a detailed video here.

What I will be doing in part 1, I will try to implement the service itself (Back-end) in a TDD environment. So, you will be expecting to learn three things in this article:

URL shortening service How to write tests for Spring boot efficiently Test Driven Development

Let’s first understand what is Test Driven Development:

It’s a software development process where you start with writing an initial failing test which will describe the functionality of a component and then make minimal updates to the code to make the test pass.

In simple words:

Start with writing a small test. For example, getUser_shouldReturnUser() or getUser_willReturnNotFound() which will describe the function getUser() with some assumptions. We will see later how to achieve these. Run the test, make sure there are no errors and the test should fail since you don’t code to pass this test. Now, that you have a failing test, go ahead and populate the getUser() function until it passes the test.

That’s it! as simple as that. Many people in the industry don’t do TDD or they don’t write tests at all. Writing tests after you have written the code will lead to unchecked edge cases, because of human tendency you will write only those tests which will pass. It is proven that when TDD is applied there is 40–80% reduction of bugs and failures in QA. And quality of code increases automatically.

I am guessing everyone reading this article is familiar with the Spring Boot framework. If not, then I highly recommend learning Spring Boot first. Enough said, let’s get started with the project already,

Getting Started:

Let’s go to Spring Initializr and generate a Spring Boot Maven Project:

Give a cool name to your project and in the dependencies section, we need to add three dependencies in order to get started with TDD:

Spring Starter Web Spring Data JPA H2 Database

Don’t worry we will be talking about these dependencies further in the article. Now, go ahead and click generate project:

Spring Initializr

Go ahead and open up the project in your favorite editor. I personally love IntelliJ Idea. This is how the project should look like:

Make sure the scope of the h2 database dependency is scoped to test. And the pom.xml should look something like this:

Flow of testing in Spring Boot:

In Spring Boot whenever we are writing RESTful services we have:

RestController which will be getting functionality from Services These Services get data from Repositories The Repositories are connected to the database.

So, how to TDD?

Write Spring Unit Tests for our end point i.e., functions in our RestControllers. Make them pass. Write Mockito Unit Tests for all the Services. Make them pass. Write DataJPATest Unit Tests for all the Repository functionalities. Make them pass. Write Integration tests, which will test the full flow of the API.

At the end of fourth step you should have a working RESTful API which passes all the tests.

Implementation:

We know from the system design we have two end points:

To create Short URL: get request to https://www.localhost:8080/shorten?longUrl= “http://www.example.com” To get the Long URL: GET request to https://www.localhost:8080/t566UI

Create a package Controllers in test and LinksControllerTest.java inside it.

LinksControllerTest

All we want to test here is, when there is a RESTful request is made to shorten a long URL, it should store it or get the already existing shortened URL and return it.

Note: Always remember the tests should be written in AAA format (Arrange, Act, Assert).

LinksControllerTest.java

You will get red underlines in this code, because we don’t have Link.java and LinksService.java. Create them:

Link.java

And LinkService.java can have the method shortenUrl() which returns a fake data for now. We will change it to working service later when we start testing the Service class.

LinksService.java

Now, if you run the test, you should get a failing test with 404 status.

404 ERROR

Let’s make this test pass. Create the LinksController.java and write a function to pass this test:

LinksController.java

Above you can see a simple code which talks with the service to create a shortUrl. Now, go ahead and run the test, it should pass:

So simple to follow TDD right? it may be a little time consuming but check that code quality.

As you know now our service is just returning static data. Why don’t we convert it to a working service!

Start with LinksServiceTest.java inside the Services Package of test section. We will be writing very light weight Mockito unit tests here:

There are two different scenarios how the shortUrl will be returned to user:

Lookup database and if the longUrl is found then return its respective shortUrl. Lookup database and if longUrl is not found then save it first and then return the shortUrl. One function for MD5 hashing which will spit first 6 characters of hash after a URL is hashed using MD5.

Let’s write the Mockito tests for the above points:

LinksServiceTest.java

We will get error since we don’t have LinkRepository.java. Let’s create the Repository:

LinkRepository.java

Check if the test cases fail:

Now let’s write the service to make them pass. I will be using the MD5 from MessageDigest library to generate hash.

LinkService.java

Voila!! the service is working perfectly:

Alright, let’s quickly move to testing our repository. We will be using DataJpaTest annotation to accomplish this.

LinkRepositoryTest.java

Now, you will be expecting it to pass. Guess what! it will fail.

Why? Because we haven’t setup a database which it will use to run the repository tests. For this we will be using h2 database. We have already added the dependency when we generated the project in Spring Initialzr.

Create an application-test.properties inside a resources folder within test section. And add these lines:

application-test.properties

Once you have this setup, it will still fails. Because, we haven’t annotated our Link.java for the repository to recognise it has an entity. Let’s go ahead and do that. Make sure you have default constructor cause hibernate needs it.

Link.java

Now run the tests again and it should work:

Awesome. We are almost done. We need integration test to check the full flow of the application. Let’s do that using the TestRestTemplate which we get with the spring boot.

UrlShortenerApplicationtests.java

Let’s run all the tests together now and check if everything is ok. Then we will go ahead and test it manually in Postman.

All tests passed

This should be the project structure you should end up with:

Project Structure

Inspired by : https://www.youtube.com/watch?v=a6TXg_WIcIQ&t=1144s

In the next part we will see how we can extract the longURL.

Part2: https://medium.com/@akshayjpatil11/tdd-url-shortening-service-part-2-89e8757f1824