Open hub20xx opened 8 years ago
Hi, thanks for the questions!
Like everything else in life, this is a trade-off so I'm not going to pretend there's a right answer.
Using real objects rather than doubles:
In general I find using concrete Value Objects in tests makes sense (we don't double other values like integers or strings, after all). It tends to lead to more readable tests and when a VO is broken it's been, in my experience, easy to see what the problem is even though many tests fail as a result.
I wouldn't restrict the approach to value objects either; a lot of the time when I am doubling a concrete class I stop and think about whether it would make more sense to either:
More and more I'm finding that one of these solutions seems better; either the class is connected to infrastructure or some other bounded context that should be isolated anyway, or is trivial enough to use directly.
This is something I'm constantly trying to evaluate as I do it, and my advice may well be different in a couple of years of doing it, but that's where I am right now.
The main thing is to try to make the tests very clear for others, without making it too hard to debug failures.
Hope this helped?
As @ciaranmcnulty asked me to post this: (https://twitter.com/CiaranMcNulty/status/726343910201692160)
Another point for having concrete classes of Value Objects
instead of Doubles would be the fact that the VOs SHOULD be always side-effect free.
Mocking or Doubles are most often needed to strip out the external dependencies.
Value Objects do not have these, by the definition. "
Yeah that's a good point I didn't mention.
There are many reasons for using Doubles:
None of these really apply to Value Objects except 1, which is why I focussed there, but it's worth mentioning the other reasons.
- Test isolation / localised failures - one broken component leads to one broken test
Does using doubles instead of concrete instances of a value object really lead to a better test isolation though? I'm asking because in my (minor) experience most of my value objects tend to brake when I change their interfaces. This means that if my tests were to use doubles I would have to change those tests because the double's interface has changed.
For me one of the disadvantages of not doubling a value object is that sometimes I have value objects which depend on other VOs and those VOs might also depend on other VOs. It can get quite tedious and annoying to write tests for such use cases since you have to build each value object separately. However I think this is more of a design issue than a testing (using doubling vs concrete classes) issue and it could probably be resolved by either rethinking the model or if needed using factory / builder classes.
@MarkRedeman In the simple case that if the VO breaks lots of tests break. That's all really.
I agree about construction of VOs getting tricky but then it will be tricky to construct them in your real code too - it can be solved using the various creational design patterns (I tend to like Builders)
Even if you wanted, you couldn't mock Values Objects because they are final
classes.
In this case, but there's no requirement for a VO to be final
(it's just a good idea)
@ciaranmcnulty Thank you very much for the explanation! :)
There are many reasons for using Doubles: ...
In a traditional London school sense, the primary reason for using doubles is to help you design communication between objects by exposing it. If assertions is the way to put design pressure on objects themselves, doubles is the way to put design pressure on their interactions.
My rule of thumb for all doubles is - use them when you care about the object collaboration. I find that I rarely care about collaboration with Value Objects, Collections and other simple value representations.
Hello,
I'm learning TDD / BDD / DDD and I was using your presentation (which I had the opportunity to see live by the way) as a tutorial (in the sense of going through each slide and typing and doing it on my machine).
I was wondering and would like to ask you why you don't use stubs in certain specs.
For example, for the origin and destination airports in the RouteSpec and why not defining what they will return like this:
instead of:
I'm green at TDD / BDD and I read and heard that it's best to use doubles for dependencies, that's why I was surprised to see that you instantiate the Airport value objects here.
Is it because they're value objects that you decided to use those dependencies in the Route spec?
I also noticed something similar (or at least it looks like so to me) but for a more complex case in the TicketIssuerSpec:
Doesn't this make the tests / specs more fragile?
Thank you very much for your presentation showing the process step by step and for putting the code too, I've learned a lot from it!
Take good care,
Hubert
PS: I didn't know where to ask about the code so I created an issue (even if it is not really an issue, except maybe for me having an issue with understanding those things... ;) ). Hope it's OK for you.