views:

797

answers:

8

Hi all,

After several years of following the bad practice handed down from 'architects' at my place of work and thinking that there must be a better way, I've recently been reading up around TDD and DDD and I think the principles and practices would be a great fit for the complexity of the software we write.

However, many of the TDD samples I have seen call a method on the domain object and then test properties of the object to ensure the behaviour executed correctly.

On the other hand, several respected people in the industry (Greg Young most noticeably so with his talks on CQRS) advocate fully encapsulating each domain object by removing all the 'getters'.

My question therefore is: How does one test the functionality of a domain object if it is forbidden to retrieve its state?

I believe I am missing something fundamental so please feel free to call me an idiot and enlighten me - any guidance would be greatly appreciated.

+9  A: 

What you're describing is state verification wherein you Assert on the state of the domain object. There's a branch of TDD that is called behavior verification that utilizes Mock objects.

Behavior verification allows you to specify which methods should be called and if you want, which methods aren't called.

Look into this article by Martin Fowler for more details: Mocks Aren't Stubs.

Gavin Miller
Awesome - that's given me lots some keywords to search for and loads more reading material! Thanks for the great and fast answer.
Justin
Read up on Martin Fowler - he's written a ton on the subject and is a great resource. Also I found Test-Driven Development By Example - Written by Kent Beck to be a good primer into TDD
Gavin Miller
I was considering the Kent Beck book, but some of the reviews I've seen (especially Amazon) are not that favourable. Is it definitely one you'd recommend?
Justin
I found it was a good introduction to TDD. It's a book that if you sit down, code the examples and really "work the book" so to speak, you'll gain a lot. However, if you're just going to read it, it's not worth it.
Gavin Miller
Fowler makes it sound as though this behavioural verification is very brittle and by just testing that certain methods are called through mock objects, that re-factoring the actual implementation becomes painful.After doing some other reading last night, I'm not convinced by no-getters and pure behaviour verification. I mean - you can still apply "Tell-don't-ask" even if you do have getters right? Just have them read only with behaviour oriented methods to mutate the state (e.g. Order has Status property with methods like Submit or Cancel.)
Justin
Hey Justin, I was thinking down that same road recently, but I am convinced I was wrong. Assuming you've bought into the idea of a write-only domain in the first place, then if you have getters at all, you're asking for trouble. The write-only domain principle would want you to fire an event from your domain object, or read from a projection that your domain object wrote, or something like that. Once you expose getters you're starting to expose the object's "shape", and as Greg Young says, "Domain objects have Behavior, not Shape".
Charlie Flowers
+2  A: 

A couple things.

First, when you do things like TDD to make your code testable you end up with smaller class. If you have a class with lots of private properties you can't inspect, theres a good chance it could be broken into multiple classes and made more testable.

Second, oldschool OO architecture tries to make software safe by using language safeguards to prevent things from being accessible. A TDD architecture makes software more robust by writing tests that verify what the code actually does, putting less emphasis on using language constructs to ensure what the program doesn't do.

Last, checking a property is not the only way to validate code did what it was supposed to do. The book xUnit Design Patterns documents other approaches here: http://xunitpatterns.com/Result%20Verification%20Patterns.html

Frank Schwieterman
Thanks for the quick response - the link is awesome and I'm starting to get the picture.
Justin
If you link the link you'll love the book (I did at least).
Frank Schwieterman
+4  A: 

If you're really going to go as far as to forbid retrieval of state, then you will be limited to behavioural testing, probably through a mocking framework such as TypeMock, which has the power to track the behaviour of your object. If you are able to do pure BDD, then theoretically you can assert the correctness of your entire system just by the way it's behaving.

In practice, I've found BDD to be more brittle in a lot of cases than just stateful testing. While some people might call for a certain theory, it only works if it works for you. State-based testing still makes up 90% of all the unit tests we write, and we're well aware of BDD on our team.

Do what works best for you.

womp
+2  A: 

I call a system's public input methods (i.e. I push input data into the system), and then I get (and assert) the system's output. I'm not testing the system's internal state, but rather its public/visible behaviour: Should one test internal implementation, or only test public behaviour?

ChrisW
+1  A: 

What you mention is called state testing. There's also behavior testing. The techniques used for that are Dependency Injection, Inversion Of Control, and Mocking:

All side effects of your class are implemented as method invocations on its "dependencies" -- i.e. objects supplied from the outside, usually in constructor. Then, in your unit-test, you supply a fake object instead of a real one. The fake object can remember if its' certain method was called, and that's what you assert in your test.

There exist number of Mocking Frameworks that automate mock object creation by dynamically generating classes that implement a given interface. Most popular are Rhino.Mocks and Moq.

zvolkov
+1  A: 

Hey Justin, like you, I was recently thinking about adding getters to my write-only domain object for the sake of unit testing, but now I am convinced I was wrong. Assuming you've bought into the idea of a write-only domain in the first place, then if you have getters at all, you're asking for trouble. The write-only domain principle would want you to fire an event from your domain object, or read from a projection that your domain object wrote, or something like that. Once you expose getters you're starting to expose the object's "shape", and as Greg Young says, "Domain objects have Behavior, not Shape".

That being said, I am struggling with your same question ... how do you unit test a write-only domain object? Here's my current plan: I am thinking of making my Domain Object fire a Domain Event saying "These properties changed", and in my unit test, I'll register for it before I send the "EditCommand". Check out Udi Dahan's post on Domain Events here, and also see what Eric Evans says about Domain Events.

Charlie Flowers
+1  A: 

I was wondering the same thing until I finally stumbled upon the following papers. I found them to be great primers on performing behavior verification, especially the first one providing me several "aha moments":

  1. Using Mocks and Tests to Design Role-Based Objects
  2. Mock Roles, Not Objects
Stiggler
links are broken. Here's the PDF for the second item: http://www.jmock.org/oopsla2004.pdf and here's the link to most of first item: http://msdn.microsoft.com/en-us/magazine/dd882516.aspx
ShaChris23
The second link works for me, and the first works if you change mockobjects.com to www.mockobjects.com
SCFrench
+1  A: 

OK, this answer is one year too late ;-)

But when you want to test CQRS models, you can make assertions on the fired domain events instead of assertions on entity state.

e.g. if you want to test if calling : customer.Rename("Foo") results in the correct behavior.

Instead of test if customer.Name equals "foo", you rather test if there is a pending CustomerRename event with the value "Foo" in your pending event store. (in your uow or in your entity event list depending on implementation)

Roger Alsing