Question 15 · Section 18

How Does SOLID Help in Code Testing?

SOLID principles are often called "Design for Testability." Without them, unit testing becomes a struggle against the code rather than a verification of logic.

Language versions: English Russian Ukrainian

Deep Dive (Under the Hood)

SOLID principles are often called “Design for Testability.” Without them, unit testing becomes a struggle against the code rather than a verification of logic.


1. SRP: Test Isolation

If a class has a single responsibility, you need one test class.

  • Without SRP: To test discount calculation, you have to mock the DB, email service, and cache.
  • With SRP: You test DiscountCalculator in isolation. Tests are fast, clear, and don’t fail because of DB changes.

2. OCP: Protecting Existing Tests

When adding a new feature, you write new tests for the new class.

  • You don’t need to rewrite 100 old tests because you didn’t change the old code. This is the foundation of regression stability.

3. LSP: Guaranteeing Test Correctness

LSP (Liskov Substitution Principle) guarantees that if a test passes for the base class, it must pass for any subclass.

  • Senior Technique: “Abstract Test” pattern (a base test class that runs for each interface implementation). Write tests for the interface and run them for every implementation. If one implementation fails — it violates LSP.

4. ISP: Small Mocks

ISP eliminates the need to implement (or mock) 20 interface methods when your test only needs one. This makes tests concise.

5. DIP: Swapping Reality

This is the “king” of testing. DIP allows you to break the connection with the real world (DB, network, time).

  • Through Dependency Injection (injecting dependencies via constructor), you give the service a MockOrderRepository (a mock object that returns test data instead of connecting to a real DB). You can simulate any errors (Timeout, Network Down) and verify how the code behaves.

SOLID and TDD (Test Driven Development — writing tests first, then code)

TDD is one of the best ways to understand SOLID in practice.

  • If it hurts to write a test for this method — you’ve violated SRP or DIP.
  • If you can’t create an object in a test without starting up the entire system — you have Coupling problems.

Test Performance

  • Cold Start: SOLID allows running thousands of tests without starting Spring Context. A pure JUnit test with mocks runs in milliseconds.
  • Parallel Execution: Thanks to no shared mutable state (DIP + SRP), SOLID-based tests parallelize perfectly across all CPU cores.

Diagnosing Architecture Quality Through Tests

  • Mock Ratio: If the number of mock setup lines (when(...).thenReturn(...)) exceeds the number of lines actually testing logic — the architecture is overcomplicated (SRP violation).
  • Test Fragility: If any code change breaks 50 tests across different modules — you have tight coupling and a DIP violation.

Summary for Senior

  • Testability is an important side effect of good design. But not the only one: readability, performance, and simplicity matter too.
  • Want to check your code for SOLID? Try writing a unit test without SpringExtension (a Spring annotation that loads the entire application context for the test — that’s an integration test, not a unit test).
  • DIP makes tests deterministic (you even control “current time” by injecting a Clock).
  • Remember: code that is extremely hard to test in isolation — likely has design problems. But there are exceptions (legacy code, low-level utilities).

When SOLID Is Not the Main Priority for Testing

  • Prototypes and spike solutions: Quick code for hypothesis validation — mocks and interfaces will only slow you down.
  • Purely functional code: Functions without side effects are tested without SOLID — just call them with different arguments.
  • Utilities and helper classes: Static methods like StringUtils.join() don’t need mocks or DIP.
  • Integration tests: When you intentionally test interaction with a real DB — mocks aren’t needed, DIP doesn’t help.

🎯 Interview Cheat Sheet

Must know:

  • SOLID = “Design for Testability”: without SOLID, unit testing becomes a struggle against the code
  • SRP: one test class, no DB/email/cache mocks needed to test a single piece of logic
  • OCP: new tests for the new class, no need to rewrite 100 old tests
  • LSP: test for the base class must pass for any subclass (Abstract Test pattern)
  • ISP: small mocks — no need to mock 20 methods when the test needs one
  • DIP: swapping reality via Mock — king of testability, even controls “current time” via Clock
  • Mock Ratio: if mock lines > logic lines — architecture is overcomplicated

Frequent follow-up questions:

  • How to check SOLID without Spring? — Write a unit test without SpringExtension; if it fails — there are Coupling problems
  • What is the Abstract Test pattern? — A base test class for an interface, run for each implementation
  • What is Test Fragility? — Any code change breaks 50 tests across different modules = tight coupling
  • When is SOLID not needed for testing? — Prototypes, purely functional code, utilities, integration tests

Red flags (DO NOT say):

  • “Testability is the only criterion of good design” (readability, performance also matter)
  • “Always use SpringExtension” (that’s an integration test, not a unit test)
  • “More mocks = better test” (more mocks = more coupling, fragile tests)

Related topics:

  • [[8. What is Dependency Inversion principle]]
  • [[16. How is Dependency Inversion related to Dependency Injection]]
  • [[1. What is Single Responsibility principle and how to apply it]]
  • [[7. What is Interface Segregation principle]]