TDD – Workflow of Test Driven Development to Follow SOLID Principles

solidtdd

I'm a bit confused with TDD+SOLID.

1) I've watched MVA course about test driven development
https://mva.microsoft.com/en-US/training-courses/testdriven-development-16458?l=gLxGoEwXC_2306218965

2) I have read various blogs, posts etc. stating that TDD accompanies, if not enforces, SOLID principles

OK, let's say I write a failing test, then make it work and then refactor (Red-Green-Refactor). According to SOLID principles code should depend on abstractions, not on concretions, but this "Make it work" (or "Green") step is about writing a simplest code to make test pass. As far as I've seen – all those tests are against concrete types, not an abstractions (maybe it's just for the sake of simplicity for learning purposes?)

So how should I write my unit test – should I first write code against concrete type and afterwords (in refactoring or "make it right" phase?) make the code SOLID (extract interface etc.)? Or is there some more "SOLID" approach for TDD?

Best Answer

should I first write code against concrete type and afterwords (in refactoring or "make it right" phase?) make the code SOLID

Writing test code against a concrete type is fine, and it is not a violation of the SOLID principles (or, to be more specific, of the "D" in the SOLID priciples). That is because the purpose of a typical test case is to test exactly that one concrete type it tests, not more, not less. There is no benefit in having the "subject under test" potentially mocked out from the test code. There might be cases where you have different components which all use the same interface, and you want to have a "reusable test" which can be applied to all these implementations, but to my experience these situations are rare and should not bring you to the conclusion unit tests should exclusesively call components via an explicit interface.

According to SOLID principles code should depend on abstractions

On abstractions, yes - but that does not mean all code needs to depend on a explicit interface in the sense of the interface keyword in Java or C#.

For a typical unit test, to depend on abstractions means simply just to rely on the public members of a class. That is also called the "interface" of a class, but not in the explicit sense mentioned above. That way, one also follows the "Abstractions should not depend on details" (=implementation details like private functions) recommendation of the DIP.