In Part 1 of this blog series on mocking, I covered some high level concepts. If you have yet to read that, I encourage you to do so before you read Part 2. It will help set the stage for what I will cover next.
In Part 2, we will look at how mocks are used and how they will help make you a master at writing unit tests.
For the remainder of this post, I will refer to my favorite ActionScript mocking library; Mockolate. Mockolate is an open source library written by Drew Bourne, who hails from down under. I was fortunate enough to meet Drew in person at 360|Flex in Denver this past April. I sat beside him to learn even more about how to use Mockolate properly.
I’m jealous of Drew for two main reasons. First, he’s incredibly smart and talented. Secondly and arguably more importantly, he has lots of hair that sticks up in the air and that is something I can never have.
I won’t recount how to setup Mockolate for use on your projects. Drew has lots of documentation to help you get started in that regard and I won’t duplicate his efforts. Grab the Mockolate .swc, the other dependent libraries, drop them in your libs folder and you’re ready to roll.
I will utilize the latest features of Mockolate and those require FlexUnit 4.1 or greater. If you are unable to use FlexUnit 4.1 and are stuck on a previous version and want me to write a brief post on that, leave me a comment and I’ll be more than happy. Using Mockolate under FlexUnit 4.0 or earlier requires a slightly different approach.
Before we dive into Mockolate and how to use mocking to significantly improve your unit testing, I want to discuss unit tests conceptually to get everyone on the same level. If you are unfamiliar with the art of unit testing, I will write on that topic in the very near future. Until then, let me cover some high level concepts.
A unit test is a piece of code executing another piece of code and verifying some condition at the end. In Part 1, I talked about the class under test. When writing unit tests, you are exclusively focused on the class under test and that it behaves as desired when you invoke its functions.
Unit tests written against the FlexUnit framework progress through a predictable lifecycle when executed. There are three general phases to the execution of a test case:
Though your unit tests often have many individual test functions on a test class, the FlexUnit framework actually creates and destroys an instance of your test class for each test function. For each test function, the first step is to set the test up. In this phase, a new instance of the class under test is typically constructed, any dependencies of the class under test are constructed and manually injected/set into the class under test and this includes the construction and often the preparation of mocks.
Once the test has been setup, a single test function is executed. Each function typically tests a single public function under a specific usage scenario and verifies one thing at the end. As you improve your test writing skills, you’ll find that most tests are no more than 3-5 lines of code. Consequently, you may end up with many test function. One simple public function on the class under test may execute under numerous different scenarios and have all sorts of interactions that must be verified.
After each test function on the test class is executed, FlexUnit enters the teardown phase. This provides the test an opportunity to cleanup. I have found that most of my tests do not utilize this phase since each test is self-contained and there are no side effects. In my opinion, the teardown phase is used more often when writing integration tests that have more side effects (i.e. connecting to a remote service).
Mockolate utilizes a FlexUnit 4.1 feature that makes setting up and preparing your mocks about as simple as possible. The MockolateRule is a FlexUnit rule that performs all the magic with minimal effort on your part. FlexUnit rules are AS3 classes that provide advanced setup and teardown capabilities.
In order to utilize the MockolateRule, you simply need to declare a public variable on your test class, instantiate the MockolateRule and annotate it with the FlexUnit [Rule] metadata tag as shown below.
The next step in the process is to let Mockolate generate and prepare your mocks for you. It’s so simple, you’ll be mocking in no time.
Simply identify which dependencies of your class under test need to be mocked. For each, declare a public variable on your test class and annotate each with the Mockolate [Mock] metadata tag as shown below:
During the setup phase of each test, Mockolate will generate a fake ILoginService for you and inject it into your public variable. You can declare as many mocks as you wish AND you may declare mocks as interfaces or concrete classes.
If you’re not amazed at what just happened, go back and re-read this section. Mockolate generated a fake version of the declared variable type on your behalf, created an instance of it and injected it into your variable and it took you all of one line of code and one metadata annotation for each. You did not have to write your own fake implementation.
So what does the mock do? Well, nothing yet. But, it is a fake stand-in for the real thing and you can inject it into your class under test and your class under test is none the wiser.
So far, we’ve done a lot with mostly no effort. The next step is to perform our own setup. In FlexUnit, this is done by annotating one or more public functions with the FlexUnit [Before] metadata tag. FlexUnit will invoke these functions for each test after the rules have been run (i.e. your mocks have all been generated).
What we want to do in our setup is to create an instance of our class under test and store it in a declared variable in our test class, as shown below (using our LoginCommand from part 1 as an example).
That’s it! We’re setup. We now have an instance of our class under test and it has been initialized with all of the dependencies it needs in order to work properly. It should be noted that you don’t have to set every single dependency on your class under test. Only the dependencies that are used during the execution of tests need to be set.
We’re now ready to write our first test method. In Part 1, I noted the various things we might wish to test against our LoginCommand. For reference, I’ve copied these testable scenarios below.
The only public function containing logical code in the LoginCommand is the execute() function. Since the LoginCommand is a relatively simple class with only one public function, I’ll have only a handful of tests. The execute() function accepts a single argument; an instance of LoginCredentialsVO. This class is a simple Value Object model class that contains only data. For a very simple class such as this, which happens to be a dependency of the LoginCommand, there is really no compelling reason to mock this. Since the VO class does not pull in any of its own dependencies and adds no further complexity to the unit test, I’ll simply use the real class.
Here is the test function for the first scenario:
There it is. That’s my first test. You might be scratching your head wondering what in the wide world of sports is going on. There is actually a lot going on here, despite the fact that the entire test consists of 3 lines of code. Let’s take a closer look.
Lets start with the name of the function. It might look a bit odd to you since it certainly isn’t the convention most of us use to name functions. The convention I use begins with the name of the function being tested on the class under test; execute. The next piece of the function name is the scenario being tested; I’m using valid login credentials. The third part of the name is the expected result of the test; the login service should have been invoked. I’ll cover this sort of thing in more detail in a future blog post regarding unit testing. Nonetheless, you can quickly tell what the test is doing just by reading the function. Separating the tuple by underscores makes it a bit easier to read rather than camel-casing the entire lengthy name.
The first line of code in the test function is setting an expectation (as described in Part 1). Using Mockolate’s mock() function instructs Mockolate to keep track of what happens to the loginService mock prepared earlier. The line of code essentially says please mock the login function on the login service because I expect that function to be invoked with the specific arguments listed (literal values in this case) and I expect it to be invoked one time. I did all of that with one line of code, rather Mockolate allowed me to do all of that. I can actually mock as many different things as I wish prior to executing the function I’m testing.
The next line is obvious. An instance of LoginCredentialsVO is constructed to be used to pass to the execute() function of the LoginCommand.
The last line of the test function invokes the function on the class under test that I’m testing.
If you recall from Part 1, mocking often involves setting expectations and then verifying that those expectations are met. The first line of the test function is where I set my expectations. But, where did the verification step occur? The MockolateRule that was created handles that automatically at the end of each test. It verifies everything that was mocked at the end of the test. If the expectation(s) are not met, Mockolate fails the test. In other words, if the mocked ILoginService.login function was not invoked with these specific arguments exactly one time during the test, the test fails.
If I were using a real implementation of the ILoginService, (i.e. HTTPLoginService) that actually attempted to communicate over the network and invoke a real service, the complexity increases significantly as does the probability that other factors will cause my test(s) to fail. Instead, the mock allows me to focus exclusively on the class under test. Who cares whether a login actually occurs? I’m testing that the command works as expected.
Before I show you the source code for the entire test class, let’s look at a second test that verifies the second scenario listed from above. This one is slightly different in that an error is thrown if an invalid username is passed along. The feature that allows me to deal with errors is provided by FlexUnit, but is worth examining regardless.
The test is shown below:
This test is even simpler at only two lines. Notice the metadata annotation for the test function. It adds an “expects” parameter with a reference to the fully qualified name of the class of the Error that is expected. FlexUnit will pass the test if an instance of Error is thrown or fails the test if no Error is thrown.
One rule of unit testing is that each test function should assert or verify one and only one thing. I pass a null username in the test above and verify that an Error is dispatched. However, I might also wish to verify that the ILoginService.login function was not invoked.
While I could easily combine both of these into a single test, it is important to keep them separate so that a failure easily indicates what the root cause was. Notice that I had to leave the “expects” parameter in the metadata tag because the command will still throw an Error. However, I’ve added back my mock() function, but set the expectation that this function will not have been called under any circumstances. Specifically, I’m setting the expectation that the login function on the mocked ILoginService will never be invoked with any combination of arguments.
Mockolate uses the Hamcrest library for matching. A description of Hamcrest is beyond the scope of this blog post, but feel free to read up on it. Hamcrest was ported to AS3 by none other than Drew Bourne. I told you that dude was smart.
I’ve barely scratched the surface of what Mockolate (and mocking in general) can do for you and the unit tests you write. I didn’t cover stubbing or strict vs. nice mocks or several other Mockolate features you’ll use frequently. I will save that for an upcoming post (Part 3?). Regardless, you should notice a number of things about the unit test.
I began writing unit tests to verify the correctness of my code nearly 15 years ago. At that point in my career, I was earning my living writing Smalltalk. That was a time when developers used to actually subscribe to magazines and these magazines were delivered monthly right to your door via the U.S. Postal Service. For a mere $129 per year, I got 12 monthly issues of The Smalltalk Report. In October of 1994, Kent Beck wrote an article published in The Smalltalk Report entitled Simple Smalltalk Testing. After reading that article a couple of years later, I downloaded a testing framework he wrote called SUnit and have since written too many unit tests to count.
Until recently, my unit tests were cobbled together with all of the various classes in the application. Though I’d been writing unit tests for nearly 15 years and arguably they were effective, they were complicated, brittle, difficult to maintain and even more difficult to comprehend. I violated practically every best practice relating to writing effective unit tests (but I’ll save this for another blog article).
About three years ago, I was first exposed to the concept of mocks as they relate to unit testing. This was a completely foreign concept to me and I must admit that I initially did not understand them or why they were necessary. After all, I have all of the classes in my application available to me, why on Earth would I ever need mocks?
Over the course of the past year, I really began focusing on honing my unit testing skills and I’ve come to love mocks and what they do for me. The quality and effectiveness of my unit tests have improved 1,000% and my use of mocks has made a world of difference for me. In talking with many of my colleagues and others I’ve met at conferences or on Twitter, it’s clear to me that many developers are confused and bewildered about mocking as I was. So, I decided to write about it and share with all of you in hopes that I might help clear things up a bit.
This is my first lengthy blog post and it will hopefully be the first of a handful of writings on the topic of unit testing and mocking.
Part 1 of this series on mocking and testing will focus on the concepts. Since this is primarily conceptual, I’ll not deep dive into code or frameworks until Part 2.
In this article, I will answer the following questions:
Outside of the world of software development, the term “mock” means to imitate or to mimic. A “mock” can therefore be thought of as a stand-in, an imposter or as most commonly referred to as it pertains to software development, a fake.
Fakes are often used as stand-ins for dependencies of the class under test.
Throughout the remainder of this post, I will use a realistic, but simple example for illustration purposes. The classes in my example are not unlike classes that may exist in your application.
LoginCommand is a very simple class that executes a login service. It so happens that the login service is a separate class and therefore a dependency of this class. Notice that the login service is expressed as an interface and that there is some mildly interesting validation logic.
ILoginService is a dependency of the LoginCommand and is a simple interface declaring only two functions; login and logout.
LoginCredentialsVO is a simple model class that wraps two pieces of data required to login; the username and password. The “VO” suffix identifies this class as a special type of model known as a Value Object.
Given this small collection of application classes, I would likely choose to unit test the LoginCommand as it contains both logical code and some interesting behavior that I would like to verify. Consequently, the LoginCommand would become my Class Under Test.
When you write unit tests, you are exclusively concerned with verifying the behavior of the Class Under Test for all reasonable scenarios. Conversely, you are not concerned with the behavior exhibited by any of the dependencies when the Class Under Test interacts with them during the execution of tests.
For example, invoking the LoginCommand.execute() function potentially invokes the ILoginService.login() function. However, we are not concerned with what happens when the service is invoked.
When we execute our tests against the LoginCommand, the only thing we can really test is various scenarios that invoke the LoginCommand.execute() function. After all, it is the only public function. Here is a list of scenarios we might like to test:
When we execute our tests, we must make sure that the LoginCommand has a reference to an ILoginService implementation. If that dependency is not provided to the LoginCommand, a Null Pointer Exception will result and all of our tests will end in error.
Our application will certainly contain an implementation of the ILoginService that invokes a remote service using mx:RemoteObject, mx:HTTPService or mx:WebService. If our application already contains such a class, why not just use that in our tests? After all, we need to test that, right?
Take a moment and think about what happens to the level of complexity in our unit tests if we use the real implementation of ILoginService that communicates with a remote service somewhere on our local machine or on the network. Suddenly, in order to run our unit tests, we have to have a running service somewhere. We also have to make sure that the machine running the tests is connected to the network. We must also ensure that the username and password are valid and that the invocation of the real service will not fail. What if the server-side code has not even been written yet? Pulling in this real implementation causes us to have to worry about all sorts of things that could cause our tests to fail. While testing with the real service might be a desirable goal, it is not a goal of a unit test.
Instead, wouldn’t it be cool if we could plugin a fake service that didn’t really do anything? Wouldn’t that be much simpler? If we do that, we no longer have to worry about networks and servers and real usernames and passwords. Using a fake greatly simplifies our unit testing.
So, how do we provide the fake to the LoginCommand? There are a number of ways you can probably think of. We could create our own fake implementation of the ILoginService class. That’s simple enough. There are only two functions we would need to implement. If we didn’t happen to express the service as an interface, we might instead choose to subclass the real service class and create a fake subclass by overriding the public functions.
Both of those alternatives involve a similar amount of effort and result in extra code to write and extra classes to create and maintain. Wouldn’t it be great if something could just generate the fake for us and we don’t have to worry about creating new classes and maintaining them? There are mocking frameworks that do just that. But, I’ll save the specifics of that for Part 2.
There are a handful of other issues that may result from using real application classes as our dependencies. When we write a unit test, it is essentially a class not unlike any other class. The class has code that creates an instance of the class under test, invokes a function on it and observes and verifies what happens.
If we use a real service, how is our test supposed to verify whether the LoginCommand invoked the ILoginService.login function? It is simply standing off to the side observing what happened. From a testing perspective, we only want to verify that the LoginCommand invoked the ILoginService.login function with specific arguments.
So, let’s summarize why we mock. First and foremost, we use fakes to simplify our tests. Secondly, there are certain types of verifications that are difficult or outright impossible without using fakes.
You might be wondering at this point, why there was no discussion of making a fake UserCredentialsVO. While you certainly could do that, what benefit would there be? This application class is sufficiently simple and its use in unit testing scenarios does not introduce additional complexity.
When it comes to mocking, there are only 3 things you really need to worry about; stubbing, setting expectations and verifying.
Some unit test scenarios don’t involve any of these, others involve only stubbing and others involve setting expectations and verifying.
Stubbing is the process of telling your fake how to behave when it is interacted with. You can generally stub public properties (those with getters and/or setters) and public functions.
When it comes to stubbing functions, you have a lot of choices typically. You may wish to return a specific value, throw an error or dispatch an event. Further, you may wish to indicate that the function behave differently depending upon how it is invoked (i.e. by matching the types or values of the parameters passed to the function).
If this sounds like a lot of work, it can be, but it generally isn’t. One great feature of many of the mocking frameworks is that you need not stub void functions. Nor do you have to stub any functions that are not invoked or properties that are not consulted during the execution of your tests.
One of the key features of a fake is the ability to tell the fake what you expect when your test runs. For example, you may expect that a specific function be invoked exactly 3 times. You may expect that it never be invoked. You may expect that it be invoked at least twice, but not more than 5 times. You may expect that it be invoked with specific types of arguments or specific values or any combination of the above. The possibilities are endless.
Setting expectations is the process of telling your fake what you expect to happen to it. Remember that since it’s a fake, nothing actually happens. But, your class under test is none the wiser. From its perspective, it invoked the function and expects that it did whatever it was supposed to do.
For what it’s worth, most mocking frameworks let you create mocks of interfaces or public classes. You are not limited to having to mock only interfaces.
Setting expectations and verification go hand in hand. Setting expectations is done prior to invoking the function(s) on the class under test. Verification is done after. So, first you set expectations, then you verify that your expectations were met.
From a unit testing perspective, if your expectations were not met, the unit test fails. For example, if you set the expectation that the ILoginService.login function should be invoked exactly once with a specific username and password, but it was never invoked during the execution of your test, then the fake would not verify and the test should fail.
There are many benefits that are to be had by using mocking instead of real application classes. These benefits include:
My goal in writing this blog entry is to introduce you to the concept of mocking in regards to unit testing. In Part 2, I will show some code samples and show you how concise and simple unit tests are when using a mocking framework. I will also introduce you to my favorite mocking framework for AS3, but include references to others that I’m aware of.
I hope that you found this article helpful and I welcome your feedback, questions, comments and input.