6 Excuses for Not Writing Unit Tests
Why don’t we do unit testing?
I started out intending to write an article on unit testing and the philosophy and process behind that.
I wanted to talk about the satisfaction that comes from completing a set of changes to a project and being able to deploy them with the reassurance that several hundred unit tests were passing and there was a minimal chance of something bad ending up in production.
Then I realized that most of the projects I have ever worked on (over a long career in the computing industry) did not use any kind of unit testing. So I thought it might be useful to examine the various reasons that unit testing was not used and the impact on these projects.
There Are No Testing Tools!
This was a pretty good excuse when I started programming for a living back in the 80s. Writing avionics code in pascal, we did write tests, but pretty much had to roll our own testing framework. No fakes, mocking, or DI here.
But if you’re writing code today in .Net/C# with Visual Studio there is no excuse for not testing any non-trivial code.
VS Code has a built-in test runner, and other test runners are available. Fake and mocking frameworks are widely used. My field — Dynamics CRM — has an excellent mocking framework in FakeXrmEasy. There is also excellent CD/CI support in Azure DevOps so that unit tests can (and should) run as part of your automated build process.
When using JavaScript, particularly in Microsoft Dynamics CRM, I’ve found it hard in the past to implement any kind of unit testing strategy.
However, a recent series by Scott Durrow shows the way ahead — using TypeScript built into a webpack with lots of early binding, mocks, and unit testing goodness to finally show us the way to producing streamlined, tested, quality “JavaScript” web resources.
Most JavaScript customizations that I have come across probably started as a quick fix to add some customization to a form.
Several years later that quick fix will have grown into a monster. Most Dynamics CRM JavaScript code has no formal testing or builds process.
In the worst case, the only copy of the code is in the production CRM server. There’s no source code repository, no “one source of truth”, no change tracking, and devs can edit the code in a bare-bones text window in a browser (on the production server!).
Testing means making sure the edited JavaScript file doesn’t throw up any obvious errors when the form loads. Just do a quick test to make sure that the feature you are implementing more or less works. It’ll be fine, won’t it? (not!). Regression testing? What’s that?
The Microsoft Power platform is another area where unit testing is still a “work in progress”. Many organizations just seem to create reams of flows and power apps with no thought to testing or ALM. The flow is broken! Who changed it last! What’s changed since last week? What’s it meant to do? Are there any tests?.
Fortunately, Microsoft seems to have at least recognized there might be a problem with the recent introduction of Power Apps Test Studio.
We Don’t Have Time To Do Testing!
The customer wants us to ship something now. Just write some code. Get it out there. No time for this ivory tower software engineering BS about unit testing!
How often have you heard that?
This approach usually seems to work for the first few weeks. Then productivity slows down as you slip into a morass of inexplicable bugs and side effects. Work harder, burn the midnight oil. Get more bodies into do manual testing!
It doesn’t have to be this way. I’d say you don’t have time not to do testing.

Look at the graph above. The orange line shows the “No testing” project.
Initially, time is saved by not doing any testing.
As more and more features are implemented the burden of (manual) regression testing grows exponentially. Every new feature added carries the extra burden of regression testing what has gone before.
Soon your project will be faced with having to compromise between quality, cost, and time taken to implement each new feature.
So yes, it may initially take you two or three times longer to write a good unit test than to test your feature by hand. But after two or three cycles of regression testing, you will be ahead — and it will only get better.
We Find It Too Hard To Write Tests!
It’s absolutely true that writing tests are hard. Writing good tests is even harder. Not writing tests is harder still (or do you really enjoy manual testing of the code your predecessor wrote 5 years ago???)
If your developers don’t know how to write good tests, they’re probably not good developers (yet). But they can learn.
Like almost everything writing good tests is something that improves with practice. The more you do it, the faster and easier it gets.
Get your best developers to write “model” tests. These can be used as templates by your less experienced developers to create their own tests.
Create testing base classes. I often do this to encapsulate frequently reused functionality and to simplify the individual test cases.
Unit Tests Are Wasted Effort!
When I spend time writing unit tests I never regard this as wasted time.
If I write code and test it manually, I regard this as wasted effort.
What do I have at the end of a series of manual tests? The code worked when I did the tests, but if I change the code I’m just going to have to repeat those tests (or more likely not bother…)
If I create automated tests then I have a suite of tests that I can re-run at any time to verify that the code still works in the way I intended when it was written.
More to the point, if I leave and a colleague takes over this code, they then have a suite of tests that they can use to verify that their changes have not broken it and the code still works in the way that I expected it to.
Manual testing is wasted effort — manual tests have zero residual value (and are usually undocumented, and hence unrepeatable). Automated tests can be used in years to come to prove that your software still works as intended.
But We Waste Too Much Time Fixing Failed Tests!
Did I mention it's hard to write tests?
The purpose of a unit test is to test the core functionality of your program. If you’re not sure what your program does (and this is more common than you’d think) then you will not be able to write robust tests.
If a test fails, this means that your software is no longer doing what you originally expected it to. This may be good — if you have changed the requirements (but then should you not have changed the test first to reflect the newly expected behavior?).
It may also mean that you have broken your code. At the very least you are now aware that there is an issue that needs to be resolved.
The first step in writing robust tests is understanding exactly what your software is supposed to do. That can’t be a bad thing, can it?
Test-Driven Design (TDD) means that your code needs to be designed with at least some thought given to how you will test it. I would suggest you think about SOLID principles and DRY, and how they apply to the code you are writing. That will always make your code better, and far, far easier to test effectively.
My experience is that this leads to better code in every way.
But Our Code Was Never Designed To Be Unit Tested!
One of the hardest things is trying to write tests for existing code. It isn’t designed to be tested, and you’ll often drive yourself to distraction by trying to test code with no specification — the code that tries to do numerous different and unconnected actions (remember the “S” in SOLID?).
Maybe the code was just not well written in the first place?
Ideally, you write unit tests when you write the code. Trying to come back and write tests for existing code usually highlights the fact that the existing code is poorly designed, and lacks clarity over its requirements.
This often leads to a need to fix and update the existing code. Depending on where you work this may or may not be seen as a good thing!
Closing Thoughts
How much unit testing is enough?
As a rough rule of thumb, I would say that you should be writing at least as much unit test code as the code you are testing. Often considerably more.
Writing unit tests is still faster than not writing tests and then spending time later in the process trying to debug errors in the finished product.
What is the benefit of all this?
The end result of unit testing is a set of tests that can be run during your build pipeline that will block any breaking changes from being merged into your code, or from being deployed to any test or production systems.
Unit tests will save you time in the long run, and allow you to deliver a better quality product, more rapidly, and with fewer resources.