DEV Community

Thomas Hansen
Thomas Hansen

Posted on • Originally published at Medium

Unit Testing is the *REASON* why your Code Sux and has Bugs

Our industry is full of assumptions. The most dangerous assumption is the belief in that we need unit tests. This is a false belief and has become a self fulfilling prophecy, resulting in cognitive complexity, that has probably been the reason why so many software projects fails ...

If you believe you need unit tests you have to modify your code to make it testable. Modifying your code to become "testable", typically implies adding an IoC container to it, because you need to be able to change the underlying service implementations for your unit tests. Great, you now have turned one file into 4 files. If we imagine a simple C# controller that needs to be tested, returning items from a database, we've now turned a single action script endpoint into 4 files.

  1. Interface declaration
  2. Service implementation
  3. HTTP controller
  4. IoC wiring and configuration

In addition, if you add data repository pattern to your solution, you end up with a total of 9 files, with 120 lines of code. Below is the same code in Hyperlambda

.arguments
data.connect:todo
   data.read
      table:items
   return-nodes:x:@data.read/*
Enter fullscreen mode Exit fullscreen mode

Below you can see the same code written in C# for a "testable project". Which version do you think has the most potential for a bug?

Testable code

By believing that you need unit tests, the belief itself has turned into a self fulfilling prophecy, because that belief resulted in 22 times as much cognitive complexity. I need to emphasise, that if you've got to touch 9 files and 120 lines of code to modify a simple HTTP read endpoint, you actually need unit tests. But the only reason why you've got 9 files and 120 LOC is because you thought you needed unit testing in the first place.

If you instead choose to believe that you do not need unit tests, you can drop your IoC container, your interfaces, your service implementations, etc, etc, etc, until you're left with 5 lines of code ...

.arguments
data.connect:todo
   data.read
      table:items
   return-nodes:x:@data.read/*
Enter fullscreen mode Exit fullscreen mode

In addition, by unit testing indeterministic code, you're not testing your code, you're testing your mock objects! Implying your unit tests have no real purpose, and only exists because of that you falsely believed they held value. Regardless of how many unit tests you create, and how many mock objects you declare, I guarantee you that there are edge cases you've not checked.

Because of the added cognitive complexity you had to create to support unit tests, your code has basically become 22x as complex to maintain.

Facts are, 90% of all unit tests you've created throughout your entire life as a professional software developer, has probably caused more harm than good.

Dynatrace image

Highlights from KubeCon Europe 2025

From platform engineering to groundbreaking advancements in security and AI, discover the KubeCon Europe 2025 insights that are shaping the future of cloud native observability.

Learn more

Top comments (0)

Redis image

Short-term memory for faster
AI agents

AI agents struggle with latency and context switching. Redis fixes it with a fast, in-memory layer for short-term context—plus native support for vectors and semi-structured data to keep real-time workflows on track.

Start building

👋 Kindness is contagious

Explore this insightful write-up, celebrated by our thriving DEV Community. Developers everywhere are invited to contribute and elevate our shared expertise.

A simple "thank you" can brighten someone’s day—leave your appreciation in the comments!

On DEV, knowledge-sharing fuels our progress and strengthens our community ties. Found this useful? A quick thank you to the author makes all the difference.

Okay