Skip to content

The Inseparable Foundation for Quality

Why Code Without Tests Can Never Truly Be Clean

White daisy flower

Photo from Ron Whitaker on Unsplash

The Challenge of Testing

Testing is a multifaceted topic that is handled differently in every project and team. The discussions are endless: 100% test coverage or not? Unit tests versus integration tests? What should be mocked and what shouldn't? But one thing is certain: Code without tests is not clean code.

The Vicious Cycle of Lacking Experience

I frequently observe that the core problem is a lack of experience. This experience is gained through actively writing tests—and here the problematic cycle closes: Tests appear complex, one doesn't know how to test certain aspects, some components are difficult to mock, the amount of testing seems overwhelming—so one abandons it altogether. The situation becomes even more challenging when TDD (Test-Driven Development) suddenly comes into play. The best solution: Collaboration with experienced colleagues or coaches who have already mastered these hurdles. Because as is often the case: Everything is simple when you know how to do it right.

Fundamental Facts About Tests

  • Writing tests requires discipline, especially with TDD

  • Tests initially mean additional effort

  • The same clean code principles apply to tests: meaningful names, good formatting, sensible comments

  • The F.I.R.S.T. rules must be observed, which requires additional knowledge

  • Tests provide certainty about the system state, especially during releases

  • They save enormous amounts of time by early detection of unintended side effects

  • Properly implemented tests give developers a high degree of security

  • From tests, one can excellently learn the business logic of a system

Key Principles for High-Quality Tests

Without going into detail about TDD (which would require its own article), here are the most important aspects:

Readability is crucial: Tests are code that is read by other developers. The business logic must be clearly recognizable. Tests should be compact—ideally structured according to the Given-When-Then pattern. Reusable components can be outsourced to special classes like test data factories.

One test—one verification: Each test should check exactly one aspect. This way, when failures occur, you can immediately and clearly identify what isn't working. This requires more effort initially, but pays off in the long run and becomes a natural way of working.

Domain-specific test language: Helper classes that provide a domain-specific test API greatly facilitate writing tests. Repetitive tasks are encapsulated, which increases motivation for testing.

Following F.I.R.S.T. Principles

In Clean Code, we talk about F.I.R.S.T. tests:

  • Fast: Tests must be quick to execute

  • Independent: Tests must not depend on each other

  • Repeatable: Tests must be reproducible in any environment

  • Self-Validating: Tests must clearly indicate pass/fail

  • Timely: Tests should be created before or alongside production code

The Right Balance in the Test Pyramid

All types of tests have their justification and advantages. Not every component needs all types of tests implemented. Unit tests form the foundation, integration tests should be used strategically, and modern end-to-end tests offer an excellent cost-benefit ratio with the right tools.

The Most Important Points at a Glance

  • Clearly represent business logic in tests

  • Write small, focused tests

  • Perform one verification per test

If the principles for high-quality tests are not adhered to, tests can quickly become a burden. Therefore, it is crucial to establish standards and consistently verify them in the code review process. Only when the entire team internalizes these principles will the enormous benefits continuously emerge. Otherwise, code quality can quickly degenerate.

Author

Sebastian Bergandy
Sebastian Bergandy