I've been reading quite a lot about TDD, especially about various practices and experiences, dos and don'ts and I'm still puzzled about several aspects after trying to apply it on a Spring Boot application with persistence and REST, all packaged by feature.
Many blog posts and answers here on StackOverflow suggest that we should test the interface and not the implementation. However, examples, like those in "Growing Object-Oriented Software, Guided by Tests" by Steve Freeman and Nat Pryce, suggest quite a different approach, since all of them test implementations mostly, asserting number of method calls, etc. So our tests actually become dependent on the implementation itself. Of course, we can use inversion of control - pass the dependencies via constructors and mock them out in our tests, but is there really a point in mocking, let's say, a CRUD repository?
Maybe I'll give you a simple example to better picture this situation. Let's say we have a multipage user information form, and each form page has to be saved separately.
So, the planned structure of the information package could be like this following package-by-feature approach:
com
.. example
.... user
...... information
........ basic
.......... + BasicInformationDto
.......... + BasicInformationService
.......... - BasicInformationServiceImpl
.......... - BasicInformationDao
.......... - BasicInformationRepository
........ additional
.......... + AdditionalInformationDto
.......... + AdditionalInformationService
.......... - AdditionalInformationServiceImpl
.......... - AdditionalInformationDao
.......... - AdditionalInformationRepository
........ + InformationRestController
+ is public and - is default access modifier
My first idea:
What if I later decide to use repository`s #saveAndFlush? Is it normal that a unit test needs to be refactored because of such a small change? And if I test only the interface, how do I test different implementations with different dependencies implementing it?
So how, using TDD, would one design, for example, the BasicInformationService`s save method if it only maps a DTO object to a DAO and then persists it using BasicInformationRepository?
Briefly, BDD (behavior-driven development), a refinement of TDD, starts with acceptance tests which test the entire stack, then test-drives details with unit tests as necessary. You can unit-test every class if you want, but you don't have to, and I don't where it doesn't add value. In the case you give, I suspect there would be no need to unit-test most of the components.
It is perfectly normal to target a known design when doing TDD/BDD, either because your framework requires it or because that design is already established in other vertical slices of your program. Only the most extreme TDDers start without a framework. What you don't want to do is make up a big design that your framework doesn't require and that testing and refactoring haven't told you yet that you need.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments