As a software engineer, sometimes you feel like the world is collapsing upon you. You’ve been working on a story or feature for weeks and there is no end in sight. You keep getting calls from your teammates about bugs from the last feature you completed. Your team is starting to discuss how to implement the next phase of your product. You can’t get a handle on everything and you feel crushed and demoralized. It’s time to take a long hard look at what you’ve been doing and figure out a way to remove some of your stresses. If only you could guarantee your code is working how it’s supposed to be working. But wait, you can! Let’s take a deep dive into Unit Testing, what it is, how to write them, and how do they impact your productivity.

Defining Unit Tests

Let’s take a minute to set a baseline. Unit tests are a form of automation testing. They are focused specifically on the smallest testable unit of functionality. Depending on your code, the smallest unit might be a class or a function or part of a function. I try to write functions with the Single Responsibility Principle in mind which keeps my units to the size of a function. The goal is to verify the unit is fit for purpose or executing as expected.

Since units are such a small part of your application you should expect to have lots of tests. You also want them to run as fast as possible. Speed is important because unit tests are your first level of feedback. I could go on a rant about Test Driven Development practices but I’ll save that for another post. As you write a few lines of code you want to verify it works as you expected. The most important factor is the speed of controlling external dependencies.

Isolation, Mocking, and Testing

External dependencies are anything outside the function or unit being tested. For example, if you write a function to calculate sales tax in the state of Pennsylvania, your function may call a repository function to retrieve the percent sales tax from a database. In this case, we need to mock the repository and results returned for the scenario you’re testing. This technique is called Isolation, it helps to keep your tests running fast.

Nested Ojbects
Isolated Objects

I can already hear a few of you reaching for your mouse and keyboard to tell me I’m completely crazy. You might argue you need to make sure the two functions play nicely together, and you’re right. That is the definition of an integration test, a topic for another post.

By implementing isolation in your tests you control what you’re testing at a very granular level. You control the test inputs, like parameter values, and external responses, like repositories, services, and databases. You will have to write many tests to cover each scenario that makes your code fit for purpose and you will need to write separate tests to cover each part of your application.

Boost Productivity

As you add unit tests you’ll trust your code more. The code is doing what it’s supposed to do and you have a test to prove it. As you add functionality you trust you’re not creating bugs because you have tests that will fail when you break something. Best of all, it’s a fast feedback loop. I know, I know, we all write perfect code the first time but when we need to refactor or fix a bug, unit tests are a safety net that make your day to day work faster and easier.

Over time, the benefits start compounding. It starts with trusting the code you write but soon you might notice other business units trust you too. Trust is hard to build but worth the effort. You might notice the strategy team trusts your delivery estimates, the support team trusts the upcoming release is bug free, or your customers trust your company enough they tell their friends. As trust grows, new opportunities will be presented to you. It could be anything from speaking at a technology conference, sitting on a team to discuss the future of the product, or stepping into a new role.

Nothing in the blog post is new. Unit Testing has become a basic tenant of modern software development. By isolating functionality, mocking external dependencies, and verifying the output of the unit under test you dramatically increase the quality of the code you write or refactor. When the quality of code increases you’re able to find ways to boost your productivity. You’ll start trusting the code you write and spend less time manually testing and retesting. You’ll feel safer refactoring existing code because you will have tests to verify you didn’t break the functionality. The rest of the business will start trusting you more and more. All of these things will reduce your stress, free your time to learn new things, and you may be offered new opportunities to make the business and product successful.