Skip to content

💎 The Art of Unit Testing

A Perspective on Testability and Long-term Maintainability

Section titled “A Perspective on Testability and Long-term Maintainability”

In senior-level engineering, unit testing is not about “checking a box” for code coverage. It is a design tool that ensures architectural integrity, provides a safety net for refactoring, and serves as living documentation.


1. The Mindset: Testing as a Design Feedback Loop

Section titled “1. The Mindset: Testing as a Design Feedback Loop”

A Programmer views a “hard to test” piece of code as a “badly designed” piece of code.

  • Design Pressure: If you need extensive mocking or complex setup for a unit test, your class or function likely has too many responsibilities (violating the Single Responsibility Principle).
  • The Documentation Value: Tests should describe the behavior of the system, not the implementation details. If a refactor changes the internal logic but the output remains the same, the tests should not break.

2. The Core Principles of High-Quality Tests

Section titled “2. The Core Principles of High-Quality Tests”
  • Fast: Tests must run in milliseconds. If the suite is slow, developers will stop running it.
  • Independent: Tests must not depend on each other or on a specific execution order.
  • Repeatable: A test should yield the same result in any environment (local, CI, staging).
  • Self-Validating: No manual interpretation of results. It’s either a green check or a red cross.
  • Thorough/Timely: Cover edge cases, boundary conditions, and “happy paths.”

Focus on testing the public API of a component. Avoid testing private methods directly; if a private method is complex enough to require its own tests, it probably belongs in a separate, injectable service.


3. Dealing with Dependencies: Mocks, Stubs, and Fakes

Section titled “3. Dealing with Dependencies: Mocks, Stubs, and Fakes”

Programers use test doubles judiciously to isolate the Unit Under Test (UUT).

  • Mocks: Used to verify behavior (e.g., “Was the email service called exactly once?”).
  • Stubs: Used to provide state (e.g., “When I call the database, return this specific user object”).
  • Avoid “Mocking the World”: Over-mocking leads to brittle tests that pass even when the system is broken. If you are mocking your own data structures, you are doing it wrong.

Maintain a healthy balance. The bulk of your suite should be Unit Tests (cheap, fast), followed by a smaller number of Integration Tests, and a minimal set of E2E Tests.

TDD (Test-Driven Development) as a Thinking Tool

Section titled “TDD (Test-Driven Development) as a Thinking Tool”

While not mandatory for every single line of code, using TDD for complex logic helps to:

  1. Define the requirements clearly before writing code.
  2. Prevent “Gold Plating” (writing code that isn’t actually needed).
  3. Ensure 100% testability from the start.

A technique to validate test quality. Mutation testing tools (like Pitest or Stryker) introduce small bugs (mutants) into your code. If your tests still pass, the tests are weak.


  • Testing Implementation Details: If changing a variable name breaks a test, the test is too coupled.
  • Logic in Tests: Avoid if statements or loops in your test code. Tests should be dead-simple.
  • The “Ice Cream Cone” Shape: Having more E2E tests than unit tests. This leads to a slow, flaky, and expensive CI pipeline.
  • Ignoring Flaky Tests: A flaky test is worse than no test. It erodes trust in the CI/CD process. Quarantine and fix them immediately.

  • Readability: Can I understand the business requirement just by reading the test name?
  • Boundary Conditions: Are we testing nulls, empty strings, and maximum values?
  • Isolation: Is the test touching a real database or network? (It shouldn’t).
  • Assertive Precision: Does the assertion check the specific outcome, or is it too generic (e.g., just checking assertNotNull)?

“Code coverage is a useful tool for finding untested code, but a poor metric for incentivizing quality. Focus on meaningful assertions and decoupled architecture.”