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.