Using mockito in BDD

This post could also have been titled: How to avoid meta-tag-itis, as the main challenge when using mockito in a BDD approach is to avoid having to adorn every context class with all the mocks that it, or its base context creates.

In order to understand why these tags are even necessary I dug into the source code and came up with the workaround described below.

Mockito under the hood

Mockito is actually build up onto ASMock, another mocking framework.

ASMock in turn uses  FLoxy, a dynamic proxy generation library which was created for ASMock originally. In order for FLoxy to generate the byte code,  it uses the FLemit libraries.

Unfortunately the created byte code cannot just be added to the AVM (ActionScript Virtual Machine) on the fly. Instead this has to be done asynchronously before any mocks that use it are created.

As far as I could gather, this is how mockito proceeds:

  1. It reflects on the Test classes to find out for which interfaces/classes it will be required to supply mock objects
  2. It creates the byte codes for these, providing a success callback which kicks off the testrunner and a failure callback which will be called if something goes wrong
  3. once all byte code has been prepared, the success callback is invoked and mockito starts running the tests
  4. if we now request a mock for a certain type, it uses the prepared byte code to supply us with a new mock instance

Why meta-tags aren’t optimal

In order to perform the first of the above mentioned steps, mockito needs us to specify via meta-tags, what mocks we will need.

Unfortunately it is not enough to just put these tags on top of the context class that actually will instantiate them  via mock(IDependency)

Instead, every sub context class (the one containing the specs), that inherits from this context class will have to be adorned with it.

Here is an example:


[Mock(type="interfaces.IDependency")]
[RunWith("org.mockito.integrations.flexunit4.MockitoClassRunner")]
public class when_something_is_the_case extends SomeSpecs
{
    [ ... ]
}

As you can see, the RunWith attribute also needs to be added.

Here are the disadvantages of doing it in this manner:

  • clutters up the code (imagine meta-tags for six mocks on every context class)
  • not refactor friendly – as strings and thus meta-tags never are
  • not very maintainable – every time I add another dependency that needs to be mocked, I have to add another meta-tag onto each context class

Clearly not the way to go.

The Mockito class

While digging inside the source code, I found the “Mockito” class which contains the following function:
public function prepareClasses(classes : Array, calledWhenClassesReady : Function, calledWhenPreparingClassesFailed : Function = null) : void

The trick is to use this class in our custom ContextsRunner to prepare the necessary mocks before we kick off the FlexUnit test runner.

This is done inside our runWithMockito function:


        private function runWithMockito(fakeClasses : Array) : void
	{
		_allContexts.push(dummy_context_to_initialize_mockito);
		new Mockito().prepareClasses(fakeClasses, runContexts, handleFailure);
	}

In case you are wondering why I am adding a dummy context. Looking at its code explains what is going on:


/**
 * This class is included in the run contexts, to give mockito one test class
* which has the meta-tag that mockito looks for to initialize.
* Alternatively we could put it on one of our context classes, but this is more convenient. * @author tlorenz */ [RunWith("org.mockito.integrations.flexunit4.MockitoClassRunner")] class dummy_context_to_initialize_mockito { [Test] public function safely_ignore_this_little_hack() : void { } }

Fortunately this workaround is easier to use than to understand.

Using the ContextsRunner with mockito

As described in the previous post, we create an Air application to run our tests with mockito.

Inside the creationComplete handler we create a ContextsRunner instance and invoke its run method with the contexts to run and the mocks that need to be prepared by mockito:


    private function onCreationComplete() : void
    {
	new ContextsRunner().run([context1, context2, ...], [ClassOrInterface1, ClassOrInterface1, ...]);
    }

As a result we don’t need to put any meta-tags inside of our test project.

We only need to make sure, that we pass the class or interface of every mock that we will be requesting from mockito along.

As mentioned in the previous post, we also need to add this compiler argument:

  • -includes org.mockito.integrations.flexunit4.MockitoClassRunner

And of course we need to reference the mockito library

The dummy test will show up in our test results, but that should not pose a major problem.

  1. Leave a comment

Leave a comment