Someone recently pointed me towards XStream. I found this to be a fantastic library to manufacture complex object graphs to use as expectation in our mockery.
The approach is as follows:
1) Create a program which connects to the real service which returns a real object
2) Use XStream to serialise this object to disk
3) Write your unit test and use XStream to deserialise the file on disk as the object to use as expectation
That's it!
The code to serialise is as follows:
XStream xstream = new XStream(new DomDriver());
BufferedOutputStream bos = ... (create the Output stream you prefer)
Person p = new Person(firstName, lastName);
xstream.toXML(p, bos);
//To unmarshall
BufferedInputStream bis = ...(create your FileInputStream)
Person p = (Person) xstream.fromXML(bis)
Easy isn't it? The toXML and fromXML methods are overloaded to provide different flavours.
I found myself avoiding complex factories of test objects to use in my mocks by actually using XStream to serialise the real thing and by writing the serialised form as an output file.
Enjoy!
Why want you to do this? Too much mocks is symptom that your class does too much.
But anyway your post give my "aha moment" :), to one of my ideas. Thanks a lot.
Posted by: Pedro | Thursday, 07 October 2010 at 19:19
The problem is not the quantity of mocks, but rather the objects they provide. The tests in question have only one mocked service, but the object returned by this service is complex (e.g. a typical value object). Now let's say that the class I'm testing invoked the mocked service, obtained a complex object graph from it, did some transformations on the complex object and returned the transformed object to the client (this is actually one use case).
Since I want to check whether the class under test transforms correctly a fully flagged complex object returned by the service, I'd need to manufacture this complex object and check that my class acts correctly.
With XStream, in a separate class I run the real service once, get the real complex object and serialise it on the file system. Then in my unit test, I ask the mock to return the object (through XStream) from the file system, de-facto simulating fully the real service.
The time it takes me to invoke the real service and serialise it with XStream can be counted in minutes; having to provide a factory to manufacture a fully flagged object requires ways much longer.
Marco
Posted by: Marco Tedone | Thursday, 07 October 2010 at 21:02
Sorry but Facebook connect didn't work :<, so I Twitter-around the problem ;)
I get your point but still, if your object need so heavy object graph it is "a smell".
Think about somebody new who will maintain this test, how he/she knows which collaborators/value objects are important and what kind of influence on the service behavior they have? Should I have to read this XML document to understand object graph, I would prefer to read 200 java lines :).
Moreover if the service will change. Should the test fails? and if yes what kind of information will I have?
Is there any changes which makes that test won't fail and why?
How should I prepare new test?, just record the behavior will not test if I was wrong, because I will have wrong recording.
But this is life and I understand your way and I'm also walking through such paths :)
Pedro
Posted by: Pedrowaty | Monday, 18 October 2010 at 10:37
Pedro, the same problems would apply to a unit test which manufactured the whole object. It seems to me that you are giving too much importance to the XML part of the whole thing, whereas actually the XML is just a "transition phase", a "useful placeholder" to represent our object graph. Developers would always reason in terms of POJOs, not XML; the serialised form of the POJO is not (and should not be) of interest. It's just a convenient way of manufacturing a complex object graph which a call to an operation on my API should return; if developers understand the POJO and the services producing it, they will be able to maintain the tests. There is no difference with what they would do if there was not XStream to the rescue.
Marco
Posted by: Marco Tedone | Monday, 18 October 2010 at 20:53