Investing in Unit Testing: Benefits and Approaches

Each scenario needs to be unit tested.

Post-implementation Unit Testing Demo


  • Add engineers to deliver solutions more quickly.
    • A direct effect of more purposeful, organized, and readable code

Say we’ve previously tested and implemented a global search-by-name feature, and would now like to give the end user the ability to filter the search results.

Step 7. Approve feature after all tests are successful.

Now that our code is implemented, we define test cases to check the feature in its entirety:

  1. Do the files load?
  2. Does the file text display?
  3. Is the font color of our headings blue?

Continuing with our previous example, let’s demonstrate TDD. We define and run tests for our feature (headings that display in blue font color). Assuming no syntactic issues are detected in our test, we are now ready to implement our code and rerun the test:

  1. Write tests for the first scenario.
  2. Implement code for the first scenario, reiterating until all tests pass.
  3. Repeat steps 1 and 2 for any remaining scenarios.

Step 6. Approve feature after all tests are successful.

A unit testing plan’s scope typically falls into one of three patterns:

  • The entire codebase sequentially
  • The entire codebase in order of importance
  • Just the critical parts, perhaps the portions that offer the most bang for our testing buck

Think of unit testing as an insurance policy to safeguard your project. Often, it is a person’s risk tolerance that dictates how much insurance to buy or or how extensive a unit testing plan to implement. At one end of the spectrum are those who would spend more to get more, their goal being maximal coverage for the sake of averting or preventing disaster. At the other end are those who would take their chances. Perhaps they are financially or otherwise resilient and well positioned to rebound from a loss, should one occur. The vast majority of people fall somewhere in between the two mindsets.

Step 5. Correct code as necessary.

Both approaches employ the same basic steps, with only their orders of operations differing. The following table displays these steps, while color-matching those that are identical across both approaches:

Meeting SMART goals serves a project by making the team’s progress more transparent to leadership and stakeholders. Developers are impelled to plan ahead and code in an organized manner. Each unit of code is assigned a single function, and tested to ensure that the unit performs as intended. The code boasts a separation of concerns:

  1. Each project unit supports a single objective.
  2. Each function within a unit fulfills only its own scope.

Identifying and correcting a bug’s root cause is more readily accomplished in unit-tested code. Say the search feature is not working correctly. Instead of a classic needle in a haystack scenario—checking the entire codebase for the root cause—you can revisit the unit test results in the project’s search module.

Efficient Refactoring

This discussion would not be complete without a mention of hybrid unit testing, in which we test features post-implementation and fix bugs encountered during development with TDD, adding tests for each new bug.

Technical Examples

Now we implement the code and rerun the tests. For each failure encountered, we update our code and retest, approving the feature only after testing is successful.

By its nature, unit testing segments a project into well-ordered, digestible portions. These individualized code divisions effectively translate into clearly defined SMART (specific, measurable, achievable, realistic, and timely) goals.




  • Add or swap features in a reasonable time.
    • A direct result of effectively implementing a separation of concerns

Unit testing a feature helps us to confirm that it works as expected—even if we refactor code logic, or update third-party libraries, for example.


  • Handle significantly higher-than-expected usage.
  • Identify bottlenecks more easily.
    • Indirect effects of decoupled code

Next, we write separate unit tests for the corresponding code units:

  1. The function that loads files
  2. The function that displays text
  3. The function that deals with formatting

Step 2. Implement code.

Testable code is clean, modular, and reusable in other environments.

Stable Code and Features

Step 4. Write, run, and validate tests.

We can expect that some tests could fail, since they were not developed concurrently with their corresponding features. If testing reveals any issues (e.g., if the headings don’t display in a blue font), we need to tweak the code and retest.

TDD Demo

We can inspect these scenarios in the readable Gherkin language, which is structured to present such behaviors:

Regardless of a team’s organization and communication style, reading unit tests enables developers to glean information that may otherwise be insufficiently documented, or buried under mountains of notes.

Natural SMART Goals

When it comes to testing, there is no universal standard. In fact, there is much discussion among experts on how much unit testing is necessary in order for a project to be successful. There are trade-offs between time invested and code quality. After the scope of unit testing is decided, the project manager must choose from among multiple unit testing strategies.

Unit Testing Scope

Feature: Load and display text from the files and display all headings in blue font color

    Scenario: User loads file successfully
        Given user navigates to the platform 
        And user navigates to the Import File page
        When user selects the file and chooses Import
        Then file is imported successfully 

    Scenario: File is loaded and text displays successfully
        Given user navigates to the platform 
        And user navigates to the Import File page
        When user selects the file and chooses Import
        Then file is imported
        And file text displays in its entirety

    Scenario: File is loaded and text displays successfully and all headings display in blue font color
        Given user navigates to the platform 
        And user navigates to the Import File page
        When user selects the file and chooses Import
        Then file text displays in its entirety 
        And all headings display in blue font color 

Step 5. Rerun tests.

Picking up with our previous global search-by-name example, let’s say the feature works perfectly, but is as slow as molasses. To remedy the speed issue, we implement a potential fix (e.g., we replace the algorithm) and retest. Once again, we can be confident we have not “broken” our feature that has previously tested perfectly. The feature should still pass its unit tests post-refactor.

Unit Testing Strategies

Step 1. Convert feature requirements into use cases.

To add this feature, we would create a new unit for our filtering function. We can remain confident that the unit that controls the global search-by-name feature should still pass if retested. The new unit’s code should not “break” code in other units.

Enhanced Debugging

Step 1. Convert feature requirements into use cases.

Only the interface of a unit should be tested: Internal states and properties intended to be read and/or written by other units should be excluded. Thus, if a unit is responsible for a multiplication function, we could write a test that ensures that multiplication is correctly performed (e.g., 5×7=35), but we would not investigate how the multiplication actually happens (e.g., 5×7 vs. 7×5 vs. 7+7+7+7+7, etc.).

Moreover, managers must weigh the team’s resources against the costs of implementing unit testing. Top reasons cited for opting out of unit testing include a project’s limited scope—whether due to a small team, or limited working hours when meeting a set deadline—and budget concerns.

Once we have finished this process, our TDD approach is completed.

An Ounce of Prevention

How do you really feel about unit testing? Does it make sense to shift focus away from development in order to dedicate the team’s efforts to improving the codebase? Developers don’t always relish the tedious cycles of evaluating code, mocking data, defining test group(s) and their function signature(s), writing tests, and then going back to tweak existing code.

A high-quality, bug-free application experience leads to more satisfied, loyal end users. If users recommend the app by leaving positive online reviews, or by sharing with friends and family, the app’s earning potential increases exponentially.

But adding unit tests can be as seamless and practical as checking whether the milk is fresh before you pour it in your coffee. In the long run, unit testing undeniably enhances a project’s development experience and reduces costs, as we will see in our exploration of unit testing’s advantages and the prevailing strategies for its implementation.

How Unit Testing Benefits Your Projects

Step 4. Implement code.

Well-planned unit testing affects the code’s scalability on a number of fronts, equipping us with the ability to:

Reviewing unit tests can help bring new developers up to speed on an application. When a project is segmented or apportioned to siloed teams, a review of unit tests goes a long way toward filling knowledge gaps and providing insights into the application as a whole.

The editorial team of the Toptal Engineering Blog extends its gratitude to Saverio Trioni for reviewing the technical content presented in this article.

Further Reading on the Toptal Engineering Blog:


Let’s imagine we have an application in which we want to present three text files whose headings should display in blue font color. We begin by writing the entire program for our feature, loading the files, and showing our headings, employing the best practices and separation of concerns discussed earlier. We then test and update our code as necessary.

All this translates into even more reduced costs. It’s reassuring to know that you’ve done the groundwork to avoid potential disasters.

Increased Revenue Potential

Step 3. Define test cases.

By thoughtfully incorporating unit testing into the development process, you increase your application’s quality. The app is delivered with fewer bugs and malfunctions for QA engineers to document, or for developers to modify.

In TDD, prior to writing any code, we translate project requirements into tests, feature by feature. As we have not yet implemented the software, our tests fail when we first run them. But we do so anyway, in order to confirm the integrity of our structure: If the code’s syntax is correct, the test runs and fails. But if it is flawed, the test does not run and we get a syntax error.

In our post-implementation testing approach, we proceed as follows:

  1. Implement the code for all three scenarios.
  2. Write the tests for these scenarios.
  3. Run the tests.

Having bite-size units facilitates the project’s tracking. Contrasted with a team whose milestones are unclear or faraway, the team that routinely checks off unit after unit is likely the happier of the two.

Improved Scalability

If all three scenarios pass unit testing, our code is good to go. However, if any tests fail, we must modify our code and retest until all tests are successful.

The idea of post-implementation testing can appeal to managers who tend to prioritize development in the race to submit deliverables to stakeholders. Post-implementation testing, therefore, is a far more common practice than TDD, which, in comparison, starts off slowly and requires discipline and patience throughout the project’s duration.

We have demonstrated that unit testing your project will more than pay for itself in financial savings, bug prevention, and the peace of mind it affords you.

Once a plan’s scope is decided, we’ll want to consider and adopt a strategy that works for our project.

Unit Testing Approaches

A lighter post-production workload results in lowered project costs and faster project completion. Managers can forecast and budget for curtailed QA team contract periods, scheduling upcoming or dependent projects to begin earlier, and developers can start working on new apps even sooner.


  • Split teams into smaller divisions to deliver solutions more quickly.
    • A direct consequence of modular code

Step 6. Correct code as necessary.

We have seen various unit testing approaches, but what does it mean to ready our project for clean, differentiated unit testing in practice? To start an example testing implementation, we must first provide for a separation of concerns in which each unit supports a single objective and each function fulfills a single task.

Step 2. Define test cases.

Benjamin Franklin’s cautionary saying—“An ounce of prevention is worth a pound of cure”—still holds true today. Like an insurance policy, unit testing is a worthwhile investment. We test for the assurance of knowing we have averted or prevented the potential disasters, and that is priceless.

Software developers are particularly qualified to translate their knowledge of each code snippet’s purpose into fitting tests. To revisit the coffee metaphor: Given limited testing resources, most of us would agree that sniffing the milk that could go bad is a far more valuable test than sniffing the sugar that can age gracefully on the shelf.

And let’s not overlook the fact that a dearth of negative reviews can also lead to financial success. Just as there are consumers who search out favorable information, there are also those who specifically look for critical reviews as a way to avoid a flawed product or service. (I count myself in the latter group.) It can be argued that, from a business perspective, garnering positive reviews is beneficial—but avoiding damaging reviews is crucial.

Stopgap Documentation

Unit testing is the process of running focused tests over small chunks (units) of code to check whether code behaves as intended during the course of an app’s development. Preemptively identifying glitches through unit testing reduces debugging time and saves money.

Reduced Post-production Costs

The third pattern, referred to as targeted unit testing, is often most practical, given project constraints. In this case, we cherry-pick the code to test, focusing on parts that are most critical to a project’s success.

Step 3. Write, run, and validate tests.

The industry standards are:

  • Post-implementation testing, in which developers write tests after features have been implemented.
  • Test-driven development (TDD), in which developers write code and tests together for each feature requirement use case.

Matthew Newman

Matthew Newman Matthew has over 15 years of experience in database management and software development, with a strong focus on full-stack web applications. He specializes in Django and Vue.js with expertise deploying to both server and serverless environments on AWS. He also works with relational databases and large datasets