Designing a unit test suite

January 05, 2022

unit test suite

Last time, we designed a simple system of an online bookstore. This short practice allowed us to think about certain project parts in depth and ponder about gaining the most from automated tests. That creates an excellent opportunity to learn how to look at our project from the technical designer’s perspective. That point of view is indispensable when we want to determine which part of the system requires validation the most and what kind of test granularity should we choose in those circumstances.

Today, we are going to focus on unit tests. We will walk through the main elements described recently and dive deeper into parts that seem the most attractive from the testing standpoint.

Frontend

In the previous post, we described three frontend views that are crucial for the application. Let’s see, where we can implement unit tests to prevent future problems.

Book detail seems like the most straightforward view because it fetches book data and displays them in a proper manner. However, the detail page may be essential for SEO, so we need to ensure that the code generates vital information without errors.
We can use unit validation on functions providing headers, titles, and meta descriptions. We may also verify whether the book and author description are adequately rendered. All of this is tested at a single function or a visual component level.

Another view is the list of books that we can filter based on keywords entered into the search form.
This part of the application is interesting, because we need to decide whether to use the path or the query parameters, whether we prefer our URLs to look like /s/charles-dickens/ or /s?q=charles%20dickens when the user searches for their keywords. Then, a logic translating those values from the search form into the URL, and from the URL to the API query, has to be written with the utmost care. Indeed, automated unit tests can help with that.

The last view is the page, where we can see the summary of our cart and where we may submit the form ordering the books we decided to purchase.
This place is where we can find many elements for which the unit tests could be introduced. That is usually true for all parts of the web application with many user interactions. We can start by ensuring that the overall cost of the selected books is calculated properly. Considering the titles quantities and potential user’s vouchers can complicate the tests, but also make them more vital.
Another critical issue is the update of LocalStorage whenever a user adds or removes books from the cart. Handling the interaction is more of an integration issue, and we will get back to it next time. Still, the exact logic of updating the current state of selected books is definitely a candidate for unit validation. That critical part of the system will surely benefit from additional approval.

Backend

Recently, we divided the API service into three endpoints. This section will try to recognize the pieces of the back-end application eligible for unit testing.

Let’s start from the easiest one. getBook seems like a clear endpoint, and from the perspective of our simplified mock application, we do not need to test any functions here.
However, that may change quickly if we decide to send any generated data inside the response payload. That may be especially important if we send dynamic stats or descriptions devised on the fly during the HTTP request. Every function that translates one piece of data into another is potentially qualified for automatic validation.

listBooks is also a very simple endpoint, because when we receive the list of keywords in the request, we use them to get the list of related book IDs. It is easy since we have a Keyword model. The only difficulty is efficiently querying every ID and responding with the list of Book elements to the client.
It seems like, there are more integration testing possibilities, yet on the other hand, we need to think about the way of filling the Keyword table itself. We require a script that obtains the Book data and creates proper Keyword records. Of course, the whole process is again an integration, or even a system, level testing. However, the sole logic of getting book-related data and turning them into an array of consistent keywords is a well-defined unit that is not trivial. We expect the keywords to come from the book’s title and author’s name, but we may also consider the book’s category or description. This is undoubtedly a place for comprehensive unit testing.

The last endpoint is called createOrder, which is a POST request. Most of the time, it means that there is more going on behind the scene. In this case, we should pay close attention to whether the order list is valid and whether we may actually create an order containing all the requested elements. For instance, there is a possibility that a user wants to purchase a book that is no longer available. That logic may involve an additional data model and a query transaction to ensure we won’t hit any race condition.
Nevertheless, we do not want to test database queries; we are currently interested in unit testing. Verifying the implementation that checks input from the request may be a great starting point. Validation logic for specific fields may be pretty demanding. In addition, we should consider the code that generates responses. Creating a helpful error message that the client will recognize may be more complex than it seems. Besides, when we write good granular unit tests for generating errors, we may also use them to validate related front-end logic. Of course, that requires the same technology on the client and the server, but with JavaScript and Node.js, we are ready to go.

Conclusion

We went through the main elements of our mock project and marked the parts that required unit testing. Of course, we could find far more of them if we go deep enough. Still, this is an excellent example of how and where to start when designing a testing suite.

The ability to specify proper places to create unit tests is vital to ensure system quality. Understanding how different elements are designed and how they interact is key from the architectural perspective. It turns out that this perspective helps to develop a comprehensive testing suite for your project. Cheers!