A New Graduate Software Developer’s Journey —Unit Testing

New grads are war heroes who never joined a real war! In this series, I will share the struggles that I faced as a New Graduate in my first full-time job at ÇiçekSepeti.

Image for post
Image for post

Okay, we got the whole data structures and algorithm classes. We passed the exams of genius professors and graduated from a university like war heroes. Now we are ready to build something like Jarvis. I don’t know about you but I thought I was completely ready. I made a graduate project like detecting cancer with Deep Learning, so what kind of problem could stop me?

1-) University Projects vs Production Code

On the other hand, the production code serves business for a long time. During this long-lived period, the first engineers of the code can leave work or new engineers can join the team. Perhaps, business shifts its strategy through this product and adds new features or changes existing ones. That’s why in production code we apply different strategies than university projects. We’re building the product, to keep it alive with the minimum cost possible.

2-) Understanding the Production Code

You need to code like talking to the future developer who you will never meet. From the future developer aspect, WTFs per minute!? will be readability measure for your code. At the same time, you need to assure that your code will show its harmony after any business decision, related to the product given by non-developer colleagues. That’s the maintainability.

Software that contains a lot of cruft -elements of the software that impede the ability of developers to understand the software- is much harder to modify, leading to features that arrive more slowly and with more defects.

— Martin Fowler

There are concepts to provide these features on your codebase. For example, A design pattern used appropriate place can gain flexible design to the changes, or we can find easily where we will add the new feature’s code as following the structure of the design pattern. But in this article, we will discuss another important concept that helps us to build a maintainable product. Yes, you heard about it before. With this concept, we will assure that “Even God himself could not sink this codebase!”. Yes, it might seem overconfident but Unit Testing is really crucial for an application. We hope our codebase will not have the same destiny as the Titanic. But I believe, you got the message.

3-) Unit Test Basics

Service layer for product related operations

We have a service layer to code the business logic separated from the database and from controller logic. After an operation, the system needs to update product variant stock. To inform the readers who haven’t work any e-commerce project, “product” is the shoe itself, and “variant” is each of the size options available in the shop. Eventually, we buy a variant of the product.

Let’s create a method named DecreaseProductVariantStock. When a purchase occurred this method will be called to decrease the purchased product variant stock. For example, we sold the last 34 sized X red shoes. And all other variants(size options) for this product is out of stock. In this case, we don’t want to show this product on the listing pages. So we are managing this case with a boolean value named availability. Show if true don’t show if not.

During this process, we need to check is there any in-stock product variant for the given product id.

It’s a basic business logic for an e-commerce website.

Now, let’s code the unit tests that will protect the written business logic. I am following a template to write readable tests.

Naming: Test method naming important to give quick information about the test. During a failure, the developer will look into the test and will try to understand why it failed.

Method Body: We can have a standard order to make things in a test method. I prefer to add comments for each part to make it more readable. Firstly, you will arrange the required mock data and will mock the dependencies to be able to test the service independently from other dependent services. After that, you will call the method that you test. That is the act part. Lastly, you will compare the expected and actual results, and depends on that you will produce assertions. That’s the basic flow for a unit test, mostly.

Now, let’s implement an example unit test.

ProductVariantService and ProductRepository classes are dependent components for our class under the test. So we are mocking these dependencies and trying to test our isolated method. Mocking is the setting up responses for the callee method and returning values as predefined. In the act part, we are creating our class with the mocking dependencies and calling the tested method. Finally, we are checking the result values with the assertion methods. It will throw an exception and the test will be failed.

Image for post
Image for post
Image is taken from MathWorks

Static Methods

Private Methods

Don’t use mutable values

4-) Continuous Integration Part

Continuous Integration doesn’t get rid of bugs, but it does make them dramatically easier to find and remove. — Martin Fowler

In ancient times, deploying a new version of the product was a big deal. A lot of new features come together and these feature bundles became the new version of our product. But this approach was taking so much time and effort. So software gods decided to separate all features from each other and to handle the features as deliverable units. But for this agile approach, there was a problem. In the old approach, at the end of the long testing process, we can assure that the new version of the product works with no problem as a whole. But now we got these tiny deliverable units. For each of the units, will we go through all the test process over again? This will cost us too much time. So how can we be sure, these tiny features will not break any part of the system without doing costly tests? At this point, God sent us Automated Tests.

When you made the change on the codebase, automated tests will run and will confirm your integration didn’t break anything. If any tests didn’t get the expected results, It will warn you with the assertions.

I am trying to show you the place of Unit Testing in the Big Picture. The big picture is the journey of the code from the developer’s laptop to the money maker production environment. Let’s follow the CI Pipeline from the diagram to understand the big picture and to figure out the role of the unit tests.

Image for post
Image for post

This pipeline occurs hundreds of times a day. So automated tests guarantee that result of the each build produces expected outputs with the given predefined inputs.

Before finishing the article, I want to mention to Code Coverage myth. Covered code means executed part of the codebase while tests are running. In my experience, code coverage doesn’t show anything about the solidity of your code If you didn’t follow the rules of the unit testing. Even you didn’t use correct assertions, the tested code part will be seemed covered. So don’t trust too much to code coverage or use it as a target parameter. The main goal should be to provide an assurance for the changeable part of the code. Don’t overengineer it or don’t underestimate it :).

Thanks for reading, feel free to comment!

ÇSTech

Çiçeksepeti Tech

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store