Testing software before releasing it is essential.
Ideally, we want as much testing done as possible. If we have more confidence that our code changes won’t break things, we can afford to move faster.
There are many ways that we can test software. The four main types of tests (listed alphabetically) are:
End-to-end.
Integration.
Manual.
Unit.
I’ve been in a company where we had little automated test coverage. With bigger features, long development and (manual) testing times meant that it was difficult to deploy in shorter cycles. When we sought external advice, we received a recommendation to add more tests in layers.
Be generous with unit tests. Add them to any classes where it makes sense to. These provide a basic input/output check.
Use integration tests to test multiple components together. You typically need fewer of these than you do unit tests.
End-to-end tests check that requests can successfully be made to an API and that the response is as expected.
It’s unrealistic that all tests can be automated. Some manual testing will still be needed.
The number of tests of each type decreases in each layer.
The Testing Pyramid
Image 1 shows the Testing Pyramid. Unit tests form the foundation at the base layer and are typically the most plentiful. As we head upwards, the tests gain more responsibility:
Integration tests check more components than unit tests.
End-to-end tests validate more than integration tests.
Writing software includes both development time, and testing time. We can choose to spend the testing time in one of two ways:
Retroactively. We build features as quickly as possible with no tests. Defects will be caught by QA, or (worse still) by customers. We’ll end up spending time context-switching to fix them. If no tests are written at this stage, any future changes mean it can happen again. And again. And again.
Upfront. We write tests alongside the software. This puts a safeguard in place to catch regressions. This won’t catch everything. But it’s more than nothing.
Summary
Development moves faster when you have confidence in your code. Testing provides that confidence. Once tests are automated, some of that confidence can come without any further effort from you.
There are different types of automated tests that test different aspects of the code. These range from basic class/object validation, to ensuring that entire workflows function correctly.
But automated tests can’t cover everything, and some manual testing will still be required.
It’s virtually impossible to write 100% bug-free code, especially when it becomes complex. But you have the power to do something about it. By writing tests alongside your code, you can have near instant feedback, reduce the bug count, and prevent regressions. It might feel like you’re going slower, but it will likely save you time – and stress – in the long run.
Thanks for reading!
Level up your developer skills! Sign up for free for more articles like this, delivered straight to your inbox (link goes to Substack).
Top comments (2)
Great overview of the different types of tests! I especially appreciate the emphasis on the balance between automated and manual testing.
Which testing tools or frameworks do you recommend for each type of test, particularly for C# projects?
Happy coding!
Thanks for reading!
Personally, I use NUnit for unit and integration tests. I know that xUnit has become increasingly popular lately and both frameworks have evolved to become very powerful. As I use NUnit primarily, that's the one I know best.
I also use Moq in my unit tests, and SpecFlow can be good for end-to-end tests.
As it happens, I'm also planning a few posts to help people write their first tests, so I'll be going through some of these frameworks in a bit more detail too.