Are mock objects serializable? Sound’s like an idiot’s question, since no sane guy would ever consider serializing something that doesn’t really exist – that’s like trying to go to the basement of a movie mockup building.
However, as it often happens in a programmer’s life, sometimes you’re forced to behave weird. Especially with mock objects if you’re trying to feed them into a third-party library.
What I was doing is mocking parts of my application to do unit tests on a business process workflow written with Jboss’ jBPM. Specifically, I was testing a script embedded in the workflow’s XML (which prevents me from skipping the whole jBPM business and do straight tests on my Java classes).
The script calls an object that I have mocked, and I want to verify that the result gets written to the workflow’s execution context (that’s the data storage underlying it, basically a String->Object map):
There’s one big problem: jBPM is a framework with intrinsic persistence (using Hibernate) and any object written to a workflow’s execution context must be serializable (!). As I found out (the hard way, as it is often with these things): mock objects created using EasyMock (specifically, EasyMock Class Extensions) are *not* serializable, even if the class they pose as is…
When I ran straight into NotSerializableException, I tried to find ways around it. A possible tsrategy would be to add a special type converter to jBPM that allows mocks – but changing the code to be tested for testing is bad.
I thought of a lot bad solutions, I have to admit. However, the one I finally came up with is this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public class MySerializableTest { /** * The serializable class to mock. */ public static class MySerializable implements Serializable { private static final long serialVersionUID = -242728243854443748L; } /** * The class that will be actually mocked. Neither the * {@link MockedMySerializable#readExternal(ObjectInput)} nor * {@link MockedMySerializable#writeExternal(ObjectOutput)} method will do * anything - they are just there to be mocked. */ public static class MockedMySerializable extends MySerializable implements Externalizable { @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { /* do nothing */ } @Override public void writeExternal(ObjectOutput out) throws IOException { /* do nothing */ } } } |
This does the trick: instead of mocking the class that implements java.io.Serializable, I create a subclass of it that implements java.io.Externalizable (for those who don’t know: that’s kind of the ‘big brother’ of Serializable which lets the user implement the actual serialization himself. Of course, I provide only a dummy implementation. Nothing will be serialized for real here, it’s just to keep the code that invokes serialization from crying.
Of course, the mock created must either be a nice mock or actually expect the writeExternal(..) method to be called. But that’s just a routine task…
Thank a ton! Exactly what I was looking for 🙂