Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reconciling Unit testing with OOD

TDD is all the rage these days and an ever growing number of software shops are converting to agile,scrum, etc. I can certainly see advantages of automated testing but I also see TDD as contradicting some principles of good object oriented design.

TDD requires you to insert seams in your code which expose implementation details through the interface. Dependency injection or collaborator injection violates the principle of information hiding. If your class uses collaborator classes then the construction of these collaborators should be internal to the class and not exposed through the constructor or interface.

I haven't seen any literature addressing the conflicts between writing testable code and at the same time adhering to the principles of encapsulation, simplicity and information hiding. Have these problems been addressed in any standard way?

like image 880
Julian Avatar asked May 06 '11 22:05

Julian


1 Answers

The methods and classes you think are implementation details are really seams that represent axes along which you can vary and recompose components into new constellations.

The classic idea about encapsulation tends to be too coarse-grained because when you hide a lot of moving parts you also make the code very inflexible. It also tends to violate a lot of the SOLID principles - most prominently the Single Responsibility Principle.

Most object-oriented design patterns tend to be rather fine-grained and fit well into the SOLID principles, which is another indicator that proper object-oriented design is fine-grained.

If your class uses collaborator classes then the construction of these collaborators should be internal to the class and not exposed through the constructor or interface.

These are two different things mixed together. I agree that in most cases the collaborators should not be exposed through the interfaces. However, exposing them through the constructors are the correct thing to do. Constructors are essentially implementation details of a class while the interfaces provide the real API.

If you want to preserve a coarse-grained API to target default functionality you can still do so by supplying a Facade. See this post for more details: Dependency Inject (DI) "friendly" library

like image 78
Mark Seemann Avatar answered Sep 27 '22 02:09

Mark Seemann