Testing Smarter: Part 1 – Foundations

Introduction

Testing is an essential part of software development. Whether you’re a developer testing a new feature on your local setup, a product owner doing a quick check before deployment, or part of a team with a dedicated QA tester, we’ve all interacted with testing. Many teams use automated CI/CD pipelines to test applications before deployment.

Automated testing is increasingly becoming the standard in the software development landscape. This trend is evident in job postings that frequently demand experience in Test-Driven Development (TDD) or specific testing frameworks.

It brings considerable benefits, from validating various application scenarios to preventing regression bugs and boosting confidence when deploying to different environments. But it’s crucial to remember that automated testing is most effective when used in appropriate circumstances, like any tool.

The Realistic Scope of Automated Testing

While complete testing automation and 100% test coverage may seem ideal, the reality is more nuanced.

First of all, human factors are still in play. The efficacy of automated tests is tied to our comprehension of application behavior. If our assumptions are incorrect, these errors will be reflected in the tests, leading to potential bugs slipping through. Consequently, developers may find themselves painstakingly reproducing and resolving these issues. Human intervention also becomes necessary in situations involving brittle tests. These tests may necessitate retries or exclusions, especially when depending on unreliable third-party integrations. Finally, manual (acceptance) testing remains crucial to a balanced testing strategy.

It’s essential to note that automated testing can extend the development cycle due to various factors. One of those is pushing for the last mile of 100% test coverage, which usually provides diminishing returns. Other factors include misaligning the testing scope or defining boundaries that complicate testing. Avoiding these pitfalls is among the key topics in this blog series.

Unit and Integration tests

Our focus will primarily be unit tests, with some attention also directed toward integration tests. Let’s consider the term ‘Unit’ in ‘Unit Tests’; while we won’t provide a strict definition, it’s worth asking: what does a ‘unit’ represent exactly?

A ‘unit’ could refer to a function, a class, a group of classes, or even an entire application behavior flow. Essentially, it’s a ‘logical’ unit, defined by what seems logical to the individual developer.

The absence of a strict definition isn’t necessarily problematic. However, it can become an issue when developers interpret ‘unit’ too rigidly, resulting in a disconnect between their understanding and the actual testing requirements of the application.

What’s Next in This Series

With the fundamentals now established, we will delve into two consecutive deep dives, highlighting common pitfalls observed in real-world projects with examples provided in C#. Following these two posts, we will wrap up the series with a conclusion. Follow us on LinkedIn, and stay tuned for the next part!

Other posts in this series: