What’s the point of all this mockery?

I’ve jumped in with both feet, without pausing to explain why I’m doing it – so, where do mock objects fit into my daily testing behaviours?

  • when the system under test relies on an expensive resource
  • when the system under test relies on a live resource
  • when the system under test relies on a resource that doesn’t yet exist
  • when I want to ensure that the system under test uses the resource correctly

I had to build a couple of client applications recently (twitter and flickr, since you ask – talk about re-inventing the wheel …), which interacted with what I consider expensive resources – firstly, I was contacting the remote flickr servers and awaiting their response each time I tested; secondly, the twitter API puts limits on how often it’s called, which means that I could run out of calls pretty quickly if every test made at least one call, and all tests were run each time I compiled the movie.

A couple of years ago, we built a googlemaps-stylee flash app for a certain weekend-break company to allow users to choose chalets (/lodges/huts/accommodation units – bizarrely ‘accommodation units’ was the official term) online. The units’ availability was updated in real time, so the app had to query the server for the latest data. The only problem with this was that the server application was still under design – it didn’t yet exist.

I’ve also worked with database developers who haven’t yet finalised their DB structure, and who keep dropping and re-building the database, which means deleting all the data that my test scripts rely on.

You only need to experience difficulties such as these a couple of times to realise that it’s imperative to have control of the remote/live/non-existent/under-development resource in order for the tests to be of any use.

The good news is that – in most cases – it’s possible to define an API for communication with the resource even before it exists, and that’s what makes mock objects so useful – they can honour the API, thus enabling the code we build against the tests to work against the resource when it’s ready.

Strikes me an example might be useful. Twitter suit you?

I have a TwitterView object, which takes a TwitterProxy which in turn communicates with the Twitter servers. I know it’s terrible – aren’t these chaps supposed to be cleanly separated? The TwitterView receives an event when the proxy has done all its loading, and then can populate the relevant TextFields. Easy, innit.

  1. public class TwitterView extends Sprite {
  2.        
  3.         private var title:TextField;
  4.         private var tweets:TextField;
  5.         private var proxy:ITwitterProxy;
  6.        
  7.         public function TwitterView(proxy:ITwitterProxy = null) {
  8.             this.proxy = proxy;
  9.             initView();
  10.             setTitle("Hello World!");
  11.         }
  12.        
  13.         public function getTitle():String {
  14.             return title.text;
  15.         }
  16.  
  17.         public function setTitle(title:String):void {
  18.             this.title.text = title;
  19.         }
  20.        
  21.         public function setTweets(tweets:Array):void {
  22.             this.tweets.htmlText = tweets.join("\n\n");
  23.         }
  24.  
  25.         override public function toString():String {
  26.             return "[TwitterView]";
  27.         }
  28.  
  29.         public function init():void {
  30.             if(proxy == null) {
  31.                 proxy = new TwitterProxy();
  32.             }
  33.             proxy.addEventListener(TwitterLoadEvent.TWITTER_LOADED, onTwitterLoaded);
  34.             proxy.init();
  35.         }
  36.  
  37.         private function initView():void {
  38.             title = new TextField();
  39.             title.autoSize = TextFieldAutoSize.LEFT;
  40.             addChild(title);
  41.            
  42.             tweets = new TextField;
  43.             tweets.width = 500;
  44.             tweets.autoSize = TextFieldAutoSize.LEFT;
  45.             tweets.wordWrap = true;
  46.             tweets.y = title.y + title.height + 10;
  47.             addChild(tweets);
  48.         }
  49.        
  50.         public function onTwitterLoaded(event:TwitterLoadEvent):void {
  51.             setTitle(event.proxy.getTitle());
  52.             setTweets(event.proxy.getTweets());
  53.         }
  54.     }

In the onTwitterLoaded function, you can see the two most important calls that we need to make on the TwitterProxy: getTitle() and getTweets(). I put these in the ITwitterProxy interface.

  1. public interface ITwitterProxy extends IEventDispatcher {
  2.        
  3.         function getTweets():Array;
  4.         function getTitle():String;
  5.        
  6.         function init():void;
  7.     }

So now we have a fairly basic view, which expects its data from the proxy.

Let’s see it in action, courtesy of TwitterApp. Yep, not much happening:

  1. public class TwitterApp extends Sprite {
  2.  
  3.         public function TwitterApp() {
  4.             init();
  5.         }
  6.        
  7.         private function init():void {
  8.             var view:TwitterView = new TwitterView();
  9.             addChild(view);
  10.             view.init();
  11.         }
  12.     }

We want to practise test-driven development – write a failing test > code until it passes > write another test > refactor – so we want to write a unit test that will check the view’s title and tweets, but (a) we can’t rely on the live twitter data as it will change over time, and (b) we don’t want to run up against the limit of API calls that we can make. Time for a mock object, methinks.

Firstly, I’m using ASUnit rather than FlexUnit, so if you’re following along, you’ll need to grab that and the ASUnitMockitoTestCase bridging class that I published one or two articles ago. Let’s start with a skeleton testcase:

  1. public class TwitterTest extends ASUnitMockitoTestCase {
  2.  
  3.         public function TwitterTest(testMethod:String = null) {
  4.             super([], testMethod);
  5.         }
  6.  
  7.         public function testBasic():void {
  8.             assertTrue("failing test", 1 + 1 == 5);
  9.         }
  10.  
  11. }

Notice that we have a basic test that will show up as a fail in ASUnit, so that we can be sure that we’ve hooked everything together successfully. As soon as you see the fail, you can delete it. Note also that the call to super() starts with an empty Array – in time we’ll populate with the classes that we wish to set up as mocks.

Now, let’s pause for a think about what we want to test here – the View relies on the proxy for its data, so we want to check that the view gets its data successfully from the proxy without hitting the live Twitter servers. Oh, and the proxy doesn’t exist yet, just an interface.

I’m going to start really slowly here, forgive me – adding the assert that checks the view’s title.

  1. public class TwitterTest extends ASUnitMockitoTestCase {
  2.  
  3.         public function TwitterTest(testMethod:String = null) {
  4.             super([], testMethod);
  5.         }
  6.        
  7.         public function testViewGetTitle():void {
  8.             assertEquals("Twitter updates", view.getTitle());
  9.         }
  10. }

Immediate compile error, since we haven’t declared view, so let’s add another line:

  1. var view:TwitterView = new TwitterView();
  2. assertEquals("Twitter updates", view.getTitle());

Still no success, because the TwitterView cannot be instantiated without a ITwitterProxy, which we don’t have, so let’s mock that (note that I’ve also added ITwitterProxy to the super() in the TwitterTest() constructor).

  1. public class TwitterTest extends ASUnitMockitoTestCase {
  2.  
  3.         public function TwitterTest(testMethod:String = null) {
  4.             super([ITwitterProxy], testMethod);
  5.         }
  6.        
  7.         public function testViewGetTitle():void {
  8.             var mockProxy:ITwitterProxy = mock(ITwitterProxy) as ITwitterProxy;
  9.             var view:TwitterView = new TwitterView(mockProxy);
  10.             view.init();
  11.             assertEquals("Twitter updates", view.getTitle());
  12.         }
  13. }

Huzzah – the movie compiles and we get our failing test :) For the record, mock() takes the interface and builds an object based on it that will record all calls made on its methods – it’s very, very clever.

First thing, let’s set the mockProxy up to give us the title string that we expect – add this line above the creation of the view:

  1. given(mockProxy.getTitle()).willReturn("Twitter updates");

This beautiful line of code says: if someone calls getTitle() on the mockProxy, the mockProxy will return “Twitter updates”. Isn’t that cool? Of course, that doesn’t help pass the test just yet.

The view is expecting to receive a TwitterLoadEvent from the proxy, triggering onTwitterLoaded(), so our mock object needs to have IEventDispatcher functionality. However, because the mockObject does so much weird stuff behind the scenes that I don’t have (and don’t want to have) a clue about, I’m going to attack this another way.

  1. given(mockProxy.addEventListener(any(), any())).will(fireImmediateLoadEvent);

When mockProxy.addEventListener() is called, it will fire an immediate load event – this is mocking the request/response communication with the Twitter server. So what’s fireImmediateLoadEvent?

It’s a GenericAnswer object, which just holds a function that will be called when addEventListener() is called; in this case I want it to be like this:

  1. var fireImmediateLoadEvent:Answer = new GenericAnswer(
  2.     function():void {
  3.         // record the event and eventHandler somehow
  4.         // then immediately fire the event with the required data
  5.     }
  6. );

Of course, in the real world, the proxy will be doing this as part of its work, but because we’re using a mock proxy, we have to work around it a bit. I’ve come up with this:

  1. var d:EventDispatcher = new EventDispatcher({} as IEventDispatcher);
  2.  
  3. var fireImmediateLoadEvent:Answer = new GenericAnswer(
  4.     function():void {
  5.         // record the event and eventHandler somehow
  6.         d.addEventListener(TwitterLoadEvent.TWITTER_LOADED, view.onTwitterLoaded);
  7.         // then immediately fire the event with the required data
  8.         d.dispatchEvent(new TwitterLoadEvent(mockProxy));
  9.     }
  10. );

So now the test looks like this:

  1.     public function testViewGetTitle():void {
  2.         // create an EventDispatcher that can be used as the dispatching functionality for
  3.         // the mock ITwitterClient
  4.         var d:EventDispatcher = new EventDispatcher({} as IEventDispatcher);
  5.        
  6.         var mockProxy:ITwitterProxy = mock(ITwitterProxy) as ITwitterProxy;
  7.         given(mockProxy.getTitle()).willReturn("Twitter updates");
  8.         given(mockProxy.getTweets()).willReturn(["Tweet#1", "Tweet#2", "Tweet#3"]);
  9.  
  10.         var view:TwitterView = new TwitterView(mockProxy);
  11.         var fireImmediateLoadEvent:Answer = new GenericAnswer(
  12.             function():void {
  13.                 // add the listening class
  14.                 d.addEventListener(TwitterLoadEvent.TWITTER_LOADED, view.onTwitterLoaded);
  15.                 // then immediately fire the event – this mocks the XML-loading that really occurs
  16.                 d.dispatchEvent(new TwitterLoadEvent(mockProxy));
  17.             }
  18.         );
  19.         given(mockProxy.addEventListener(any(), any())).will(fireImmediateLoadEvent);
  20.         view.init();
  21.            
  22.         assertEquals("Twitter updates", view.getTitle());
  23.     }

For completeness, here’s TwitterLoadEvent:

  1. public class TwitterLoadEvent extends Event {
  2.        
  3.     public static const TWITTER_LOADED:String = "onTwitterLoaded";
  4.        
  5.     private var _proxy:ITwitterProxy;
  6.  
  7.     public function TwitterLoadEvent(proxy:ITwitterProxy) {
  8.         super(TWITTER_LOADED, false, false);
  9.         _proxy = proxy;
  10.     }
  11.        
  12.     public function get proxy():ITwitterProxy {
  13.         return _proxy;
  14.     }
  15. }

Mocking slavery

New to the idea of such mockery, I was very lucky to find a tutorial using the Java version which I could convert as I worked through it.

Now I’m converted – it’s a very neat and fast way of stubbing out the behaviours that I wish to code.

This morning, however, I came across a slightly trickier case to mock – at least, a case that required trial and error, as it hasn’t been documented that fully.

I have a slave interface:

  1.  
  2. public interface ISlave {
  3.  
  4.     function doSthg():String;
  5.     function order(command:String):void;
  6.     function answer():String;
  7.  
  8. }

And the behaviour I want is that when a slave is ordered to “doSthg!”, it should answer() and doSthg() pretty sharpish. So the test looks like this:

  1. slave.order("doSthg!");
  2.            
  3. verify().that(slave.answer());
  4. verify().that(slave.doSthg());

To verify().that(slave.answer()) means to verify that slave.answer was called once.

First off, I needed to define the doSthg() and answer() methods, having created a mock slave from the interface (both return a String object):

  1. var slave:ISlave = mock(ISlave) as ISlave;
  2.          
  3. given(slave.doSthg()).willReturn("done!");
  4. given(slave.answer()).willReturn("yessir!");

And then I came to the tricky bit – since I’m creating this object out of an Interface definition how can I define the behaviour of slave.order()?

Well, thankfully the GenericAnswer object literally holds the answer to that question – it is instantiated with a function thus and given to the mock slave.order (if the call parameter is correct!):

  1. var answer:Answer = new GenericAnswer(
  2.     function():void {
  3.         trace(slave.answer());
  4.         trace(slave.doSthg());
  5.     }
  6. );
  7. given(slave.order(eq("doSthg!"))).will(answer);

So now I have created an ISlave interface with three public methods, and defined how the methods interact, and precisely what parameter in order() will trigger the correct interaction. In full it looks like this:

  1. var slave:ISlave = mock(ISlave) as ISlave;
  2.          
  3. given(slave.doSthg()).willReturn("done!");
  4. given(slave.answer()).willReturn("yessir!");
  5.  
  6. var answer:Answer = new GenericAnswer(
  7.     function():void {
  8.         trace(slave.answer());
  9.         trace(slave.doSthg());
  10.     }
  11. );
  12. given(slave.order(eq("doSthg!"))).will(answer);
  13.          
  14. slave.order("doSthg!");
  15.            
  16. verify().that(slave.answer());
  17. verify().that(slave.doSthg());

P.S. Obviously, the slave should not have a order() method – that’s the responsibility of the master (e.g. master.order(slave, “doSthg!”)), but it serves to make this example work, so forgive me!

Mockito-Flex meets ASUnit

Well, that’s not a catchy headline, but it does pretty much sum it up. I’ve been playing with Mockito-Flex, a mock object framework for Actionscript 3. It’s great, and made vastly easier to pick up by a Mockito-FlexUnit bridge in the form of a MockitoTestCase that does the hard work of reporting the mocking results and validations in a way that FlexUnit can display.

Of course, FlexUnit does require the Flex framework, which bulks up the whole thing. Oh, and I’m used to using ASUnit. So I’ve written the following class that does the same job as MockitoTestCase, but for ASUnit:

  1. /**
  2.  * The MIT License
  3.  *
  4.  * Copyright (c) 2009 Mockito contributors
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  7.  * and associated documentation files (the "Software"), to deal in the Software without restriction,
  8.  * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9.  * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
  10.  * subject to the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  15.  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
  16.  * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  17.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19.  */
  20.  
  21. package org.mockito {
  22.     import asunit.framework.TestCase;
  23.  
  24.     import org.mockito.api.Matcher;
  25.     import org.mockito.api.MethodSelector;
  26.     import org.mockito.api.MockCreator;
  27.     import org.mockito.api.Stubber;
  28.     import org.mockito.api.Verifier;
  29.  
  30.    
  31.     public class ASUnitMockitoTestCase extends TestCase {
  32.  
  33.         private var _mockClasses:Array;
  34.  
  35.         protected var mockito:Mockito;
  36.        
  37.         public function ASUnitMockitoTestCase(mockClasses:Array, testMethod:String = null)
  38.         {
  39.             _mockClasses = mockClasses;
  40.             super(testMethod);
  41.         }
  42.  
  43.         /**
  44.          * Due to the asynchronous nature of the class generation
  45.          * a test needs to execute from a callback function
  46.          */
  47.         public override function run():void
  48.         {
  49.             if (mockito == null && _mockClasses)
  50.             {
  51.                 mockito = new Mockito();
  52.                 var superRun:Function = super.run;
  53.                 mockito.prepareClasses(_mockClasses, repositoryPreparedHandler);
  54.                 function repositoryPreparedHandler():void
  55.                 {
  56.                     superRun();
  57.                 }
  58.             }
  59.             else
  60.             {
  61.                 super.run();
  62.             }
  63.         }
  64.        
  65.        
  66.  
  67.         /**
  68.          * Constructs mock object
  69.          * @param clazz a class of the mock object
  70.          * @param constructorArgs constructor arguments required to create mock instance
  71.          * @param name a name used in various output
  72.          * @return a mocked object
  73.          */
  74.         public function mock(classToMock:Class, name:String = null, constructorArgs:Array = null):Object
  75.         {
  76.             return mockito.mock(classToMock, name, constructorArgs);
  77.         }
  78.  
  79.         /**
  80.          * A starter function for verification of executions
  81.          * If you dont specify the verifier, an equivalent of times(1) is used.
  82.          * @param verifier object responsible for verification of the following execution
  83.          */
  84.         public function verify(verifier:Verifier = null):MethodSelector
  85.         {
  86.             return mockito.verify(verifier);
  87.         }
  88.  
  89.         /**
  90.          * A starter function for stubbing
  91.          * @param methodCallToStub call a method to stub as an argument
  92.          * @return an object providing stubbing options
  93.          */
  94.         public function given(methodCallToStub:*):Stubber
  95.         {
  96.             return mockito.given(methodCallToStub);
  97.         }
  98.  
  99.         /**
  100.          * @private
  101.          */
  102.         protected function get mockCreator():MockCreator
  103.         {
  104.             return mockito;
  105.         }
  106.  
  107.         /**
  108.          * Matches any argument including <code>null</code>
  109.          */
  110.         public function any():*
  111.         {
  112.             return mockito.any();
  113.         }
  114.  
  115.         /**
  116.          * Equality matcher
  117.          * Example:
  118.          * <listing>
  119.          * verify(never()).that(system.login(eq("root")));
  120.          * </listing>
  121.          */
  122.         public function eq(expected:*):*
  123.         {
  124.             return mockito.eq(expected);
  125.         }
  126.  
  127.         /**
  128.          * A fluent interface for making sure call hasn't happened
  129.          * Example:
  130.          * <listing>
  131.          * verify(never()).that(operator.execute());
  132.          * </listing>
  133.          */
  134.         public function never():Verifier
  135.         {
  136.             return mockito.never();
  137.         }
  138.  
  139.         /**
  140.          * A fluent interface for counting calls
  141.          * Example:
  142.          * <listing>
  143.          * verify(times(2)).that(operator.execute());
  144.          * </listing>
  145.          */
  146.         public function times(expectedCallsCount:int):Verifier
  147.         {
  148.             return mockito.times(expectedCallsCount);
  149.         }
  150.  
  151.         /**
  152.          * A fluent interface for custom matcher
  153.          * Example:
  154.          * <listing>
  155.          * verify().that(system.login(argThat(new HashOnlyCapitalLettersMatcher())));
  156.          * </listing>
  157.          *
  158.          * A good practice is to create a matcher recording function somewhere and name it
  159.          * after the matcher. It's important to return a wildcard from the function to let it
  160.          * work with any arugment of the function
  161.          * <listing>
  162.          * function hasOnlyCapitalLetters():*
  163.          * {
  164.          *     argThat(new HashOnlyCapitalLettersMatcher());
  165.          * }
  166.          * </listing>
  167.          */
  168.         public function argThat(matcher:Matcher):*
  169.         {
  170.             return mockito.argThat(matcher);
  171.         }
  172.     }
  173. }

I’ve built this against ASUnit3, and it appears to be running fine. As you can see, it’s release under the MIT license, as is Mockito-Flex. I’d appreciate any feedback that’s going, so have a play and let me know …

Rocks into Gold

Clarke Ching – whose work I’ve been reading for a while, is preparing to publish a short parable for these troubled times. Get in touch with him via this post, and grab a copy, after all the more weapons in our armoury, the better chance we have of winning the inevitable battles.

Wacky agile zealots are at it again

This post reminded me of a long drive around Eastern Scotland at the start of this weekend.

I had a printout of the route from Aberdeen to Boat-Of-Garten from the AA website. Matt had his TomTom. Rather than shuffling papers, I agreed to use the gadget, so Matt tapped in Boat Of Garten, and off we went.

Despite knowing that Aberdeen airport is northwest of the city, and that we would be driving further northwest still, I didn’t complain when the TomTom took us around Aberdeen and southward down the coast – after all, there was bound to be a good reason, wasn’t there.

We were also extremely hungry and looking for food as much as roadsigns. (Incidentally, we found the first ever chippy that’s asked me which of a selection of batters I’d like – how good is that?).

The mileage remaining got less and less, and we were still driving along a large clear road in a fairly low-lying area, but my suspicions were rising. When we found ourselves on the Dundee bypass, I knew something was up. The TomTom was taking us to a non-existent destination, which had added two hours to our journey.

Finally, we got onto the main road north, and hammered along in the gloaming. Fantastically for a southerner, the sky remained light until 11pm, so the driving wasn’t that painful. But, even so, we had a deadline: the B&B owner wanted us there by 10pm, so we made a series of grovelling phone calls as we got closer and closer.

It stuck in my memory as just another random irritating drive until reading Those wacky agile zealots are at it again, when the greater implications became clear.

Even when the route, timings, are as clear and as well-defined as they can possibly be, we still need to keep our eyes on the road, not just for rabbits and corners, but also to check that the route is correct (or, in this case, the destination).

I want problems, not solutions!

So, there I was, quietly listening into a conference call between a couple of clients on one side, and the account manager, project manager and me on the other.

We were going through a small project that we’d just completed for the purposes of getting sign-off. We had built in the functionality they wanted, using the designs that they’d agreed to, so it was plain sailing.

And then the spanner.

Read more »

Testing Proxies in PureMVC

This post is prompted by Larry Marburger’s article, since I came across this problem a few weeks ago, and found a different solution.

The scenario
There’s this great new framework that you’re starting to use, and it’s persuaded you to turn a new leaf and unit-test your work as you go. First off, be warned this is all AS2.0, using asunit2.5, because I’m still stuck in the dark ages :(

The problem
PureMVC uses Proxy objects to access data from the model, which fire off Notifications (PureMVC-specific events) when the data is ready. However, in the case of a Proxy that loads XML before making its data available, how do we know when it’s ready to be tested?

Read more »

A grown-up conversation

Several places I’ve worked have spoken about the client in two contrasting ways: one, hushed tones suggesting that they’re too sensitive to handle whatever reality we’re dealing with; two, derision suggesting that they’re too much of an idiot to understand whatever reality we’re dealing with.

Both are clearly untrue (to greater or lesser degrees), and both serve to make our jobs harder because they distance us from the most important person in any project.

So here’s a list of questions I would like answered:

  • why do we keep secrets from clients?
  • why are we so keen to promise tight deadlines?
  • why do we try to squeeze in extra stuff for them?
  • what if we treat them as part of the team?
  • what if we made them fully aware of the repercussions of their decisions?
  • what if we made demands of them, in order to deliver
  • what if we explain how risk builds up, and what they can do to mitigate it?

Read more »

Project in distress (IV)

I particularly like this one: a week has passed, whilst the project manager has been “working” with the designer on the definition of 3D behaviour of playing cards on the site. His output landed in my in box yesterday afternoon: it was a list of cards, and the places they would sit in on the site.

This information was available in the original pitch document! So has it really taken a week to change the document format?

Finding out what’s best …

Just doing our best ain’t good enough – we need to be more savvy than that and work out precisely what’s the best thing to do first. So far, we’ve identified the conflict, and we now need to assess possible solutions.

Read more »