MiniSMock is my minimalistic approach to Mock objects, which can be extremely helpful in testing legacy code as well as code that has a lot of dependencies and is hard to set up.
I wanted something that is extremely lightweight and fits well with SUnit, witout any complex setup rules or other hassle. There are much better and more complete Mock Object frameworks out there, but for my needs the most important requirement was that it’s simple enough to use right away. There really isn’t much to it, not even something that you could call documentation, since it is just one single class. If you want to take a look, feel free to download it from VASTGoodies and use it. Let me know if you find something that is missing.
Reflecting MockObjects – A new kind of intelligence?
Somebody just did exactly that and asked me if they could possible use it in their code base which is quite defensive and uses a lot of reflection to test whether an object is ready to be answer a certain message to. So what they do a lot is ask an object if it #respondsTo: or #isKindOf: and all that nice stuff they always told you to avoid in real code 😉
So there I sat and thought: well, it’s Smalltalk, so there’s not much I can think of that should make it hard to implement in a Mock object. So what I did was implement #respondsTo: so that it first delegates the question to its superclass and if that doesn’t accepts responsibility for the message, goes through its own dictionary of selectors that should be answered. If the message is found, the Mock simply answers true. That’s all. This feature is really just an override of #respondsTo: so there’s nothing you have to do in order to use the feature.
The next two methods need some more preparation: If I want a Mock Object to answer whether it is member of a certain class or any of its superclasses, there is a need to tell the Mock Object what kind of object it is meant to represent. So the implementation of #isKindOf: and #isMemberOf: first delegates to the superclass, and if that answers false, the Mock has to hold it’s faked class name in a variable. I decided to even maintain a list of Classes that a Mock claims to be an instance of, and that is because of the third trick which I’m going to mention a little later. So with the new version of MiniSMock you can set up a Mock object and tell it to #beMockForClass: Customer. Thus it will answer the question #isKindOf: Customer with true. This way you are ready to use the Mock Object in situations where code first asks it if it is a Customer and only then sends it some message. You can send #beMockForClass: multiple times to it, so that it can behave just like a Customer and a Branch at the same time.
And this brings us to a third feature that I learned from a Customer at a testing workshop: Why not use a Mock Object as replacement for not only one object but many?
You may think: huh?
So did I.
Is Mocking a new kind of schizophrenia?
But then he told me they are using this to make setting up complex mockings easier: sometimes, code needs to navigate a complex structure of objects, like from here to the Customer, to her Address, the City and then ask it for its local tax rates. For certain tests you may not need anything else from a Customer or their Address or City but just the next object to navigate to. With MiniSMock, you’d have to set up a Mock for the Customer which answers another Mock for the Address which in turn would answer a Mock for a City, which then had some local tax rate to answer.
What if you could simply use one MockObject that returned itself every time it is asked for something it has no preconfigured answer to?
So now a Mock Object returns itself if it is asked for its #address (because nobody told it what to answer to the message #address) and also if it is asked for its #city and then answer 25.0 to the message #localTaxRate, because that is an answer that was configured. Thus you can save a lot of setup work and use one Mock Object for a complete object structure – or a subsystem that you want to avoid to start in your tests.
I thought this idea is so cool that I just had to implement it in MiniSMock and it already is in use in my testing code. Let me restate that this idea is way too good to be mine, but I am not sure if the person who told me about it would want me to give him credit in a blog post, so I’ll just say that this is a very cool idea that I simply adapted in MiniSMock. I don’t know if it is present in any other Mock Object implementation.
Because this is a change in how MiniSMock handles messages that were not pre-configured (currently it throws a dNU exception after logging the message as not understood) , I had to add a new flag to MockObject which defaults to the old behavior. That means that if you want to use a MockObject in the way I describe it here, you have to send it the message #beMockTraversal or set #mockTraversal: to true.
Don’t panic, sanity is not in danger!
So now you understand why a Mock Object can represent multiple classes and why you can send it #beMockForClass: multiple times: If your code sends any of the “intermediate” objects the message #isKindOf: or #isMemberOf:, you can make it give the desired answer. This additional step is only necessary if there is reflection in play.
I am on the road today and cannot upload the latest Version of MiniSMock (0.2) to VASTGoodies right now, but will do so very soon. Maybe I will even find the time and patience to write a little tutorial or such, but you should easily understand what MiniSMock is all about by reading the TestCase.