I am new to unit testing, and I continously hear the words 'mock objects' thrown around a lot. In layman's terms, can someone explain what mock objects are, and what they are typically used for when writing unit tests?
A Mock Object is an object that substitutes for a real object. In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways.
A computer programmer typically creates a mock object to test the behavior of some other object, in much the same way that a car designer uses a crash test dummy to simulate the dynamic behavior of a human in vehicle impacts.
http://en.wikipedia.org/wiki/Mock_object
Mock objects allow you to set up test scenarios without bringing to bear large, unwieldy resources such as databases. Instead of calling a database for testing, you can simulate your database using a mock object in your unit tests. This frees you from the burden of having to set up and tear down a real database, just to test a single method in your class.
The word "Mock" is sometimes used interchangeably with "Stub." The differences between the
two words are described here. Essentially, a mock is a stub object that also includes the expectations
(i.e. "assertions") for proper behavior of the object/method under test. For example:
class OrderInteractionTester...
public void testOrderSendsMailIfUnfilled() {
Order order = new Order(TALISKER, 51);
Mock warehouse = mock(Warehouse.class);
Mock mailer = mock(MailService.class);
order.setMailer((MailService) mailer.proxy());
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")
.withAnyArguments()
.will(returnValue(false));
order.fill((Warehouse) warehouse.proxy());
}
}
Notice that the warehouse
and mailer
mock objects are programmed with the expected results.
Mock objects are simulated objects that mimic the behavior of the real ones. Typically you write a mock object if:
- The real object is too complex to incorporate it in a unit testing (For example a networking communication, you can have a mock object that simulate been the other peer)
- The result of your object is non deterministic
- The real object is not yet available
Part of the point of using mock objects is that they don't have to be really implemented according to spec. They can just give dummy responses. E.g. if you have to implement components A and B, and both "call" (interact with) each other, then you can't test A until B is implemented, and vice versa. In test-driven development, this is a problem. So you create mock ("dummy") objects for A and B, that are very simple, but they give some sort of response when they're interacted with. That way, you can implement and test A using a mock object for B.
I highly recommend a great article by Martin Fowler explaining what exactly are mocks and how they differ from stubs.
When unit testing some part of a computer program you ideally want to test just the behavior of that particular part.
For example, look at the pseudo-code below from an imaginary piece of a program that uses another program to call print something:
If theUserIsFred then
Call Printer(HelloFred)
Else
Call Printer(YouAreNotFred)
End
If you were testing this, you would mainly want to test the part that looks at if the user is Fred or not. You don't really want to test the Printer
part of things. That would be another test.
This is where Mock objects come in. They pretend to be other types of things. In this case you would use a Mock Printer
so that it would act just like a real printer, but wouldn't do inconvenient things like printing.
There are several other types of pretend objects that you can use that aren't Mocks. The main thing that makes Mocks Mocks is that they can be configured with behaviors and with expectations.
Expectations allow your Mock to raise an error when it is used incorrectly. So in the above example, you could want to be sure that the Printer is called with HelloFred in the "user is Fred" test case. If that doesn't happen your Mock can warn you.
Behavior in Mocks means that for example, of your code did something like:
If Call Printer(HelloFred) Returned SaidHello Then
Do Something
End
Now you want to test what your code does when the Printer is called and returns SaidHello, so you can set up the Mock to return SaidHello when it is called with HelloFred.
One good resource around this is Martin Fowlers post Mocks Aren't Stubs
A Mock object is one kind of a Test Double. You are using mockobjects to test and verify the protocol/interaction of the class under test with other classes.
Typically you will kind of 'program' or 'record' expectations : method calls you expect your class to do to an underlying object.
Let's say for example we are testing a service method to update a field in a Widget. And that in your architecture there is a WidgetDAO which deals with the database. Talking with the database is slow and setting it up and cleaning afterwards is complicated, so we will mock out the WidgetDao.
let's think what the service must do : it should get a Widget from the database, do something with it and save it again.
So in pseudo-language with a pseudo-mock library we would have something like :
Widget sampleWidget = new Widget();
WidgetDao mock = createMock(WidgetDao.class);
WidgetService svc = new WidgetService(mock);
// record expected calls on the dao
expect(mock.getById(id)).andReturn(sampleWidget);
expect(mock.save(sampleWidget);
// turn the dao in replay mode
replay(mock);
svc.updateWidgetPrice(id,newPrice);
verify(mock); // verify the expected calls were made
assertEquals(newPrice,sampleWidget.getPrice());
In this way we can easily test drive development of classes which depend on other classes.
As another answer suggested via a link to "Mocks Aren't Stubs", mocks are a form of "test double" to use in lieu of a real object. What makes them different from other forms of test doubles, such as stub objects, is that other test doubles offer state verification (and optionally simulation) whereas mocks offer behavior verification (and optionally simulation).
With a stub, you might call several methods on the stub in any order (or even repitiously) and determine success if the stub has captured a value or state you intended. In contrast, a mock object expects very specific functions to be called, in a specific order, and even a specific number of times. The test with a mock object will be considered "failed" simply because the methods were invoked in a different sequence or count - even if the mock object had the correct state when the test concluded!
In this way, mock objects are often considered more tightly coupled to the SUT code than stub objects. That can be a good or bad thing, depending on what you are trying to verify.
Mock and stub objects are a crucial part of unit testing. In fact they go a long way to make sure you are testing units, rather than groups of units.
In a nutshell, you use stubs to break SUT's (System Under Test) dependency on other objects and mocks to do that and verify that SUT called certain methods/properties on the dependency. This goes back to fundamental principles of unit testing - that the tests should be easily readable, fast and not requiring configuration, which using all real classes might imply.
Generally, you can have more than one stub in your test, but you should only have one mock. This is because mock's purpose is to verify behavior and your test should only test one thing.
Simple scenario using C# and Moq:
public interface IInput {
object Read();
}
public interface IOutput {
void Write(object data);
}
class SUT {
IInput input;
IOutput output;
public SUT (IInput input, IOutput output) {
this.input = input;
this.output = output;
}
void ReadAndWrite() {
var data = input.Read();
output.Write(data);
}
}
[TestMethod]
public void ReadAndWriteShouldWriteSameObjectAsRead() {
//we want to verify that SUT writes to the output interface
//input is a stub, since we don't record any expectations
Mock<IInput> input = new Mock<IInput>();
//output is a mock, because we want to verify some behavior on it.
Mock<IOutput> output = new Mock<IOutput>();
var data = new object();
input.Setup(i=>i.Read()).Returns(data);
var sut = new SUT(input.Object, output.Object);
//calling verify on a mock object makes the object a mock, with respect to method being verified.
output.Verify(o=>o.Write(data));
}
In the above example I used Moq to demonstrate stubs and mocks. Moq uses the same class for both - Mock<T>
which makes it a bit confusing. Regardless, at runtime, the test will fail if output.Write
is not called with data as parameter
, whereas failure to call input.Read()
will not fail it.
Since you say you are new to unit testing and asked for mock objects in "layman's terms", I'll try a layman's example.
Unit Testing
Imagine unit testing for this system:
cook <- waiter <- customer
Its generally easy to envision testing a low-level component like the cook
:
cook <- test driver
The test driver simply orders different dishes and verifies the cook returns the correct dish for each order.
Its harder to test a middle component, like the waiter, that utilizes the behavior of other components. A naive tester might test the waiter component the same way we tested the cook component:
cook <- waiter <- test driver
The test driver would order different dishes and ensure the waiter returns the correct dish. Unfortunately, that means that this test of the waiter component may be dependent on the correct behavior of the cook component. This dependency is even worse if the cook component has any test-unfriendly characteristics, like non-deterministic behavior (the menu includes chef's surprise as an dish), lots of dependencies (cook won't cook without his entire staff), or lot of resources (some dishes require expensive ingredients or take an hour to cook).
Since this a waiter test, ideally, we want to test just the waiter, not the cook. Specifically, we want to make sure the waiter conveys the customer's order to the cook correctly and delivers the cook's food to the customer correctly.
Unit testing means testing units independently, so a better approach would be to isolate the component under test (the waiter) using what Fowler calls test doubles (dummies, stubs, fakes, mocks).
-----------------------
| |
v |
test cook <- waiter <- test driver
Here, the test cook is "in cahoots" with the test driver. Ideally, the system under test is designed so that the test cook can be easily substituted (injected) to work with the waiter without changing production code (e.g. without changing the waiter code).
Mock Objects
Now, the test cook (test double) could be implemented different ways:
- a fake cook - a someone pretending to be a cook by using frozen dinners and a microwave,
- a stub cook - a hot dog vendor that always gives you hot dogs no matter what you order, or
- a mock cook - an undercover cop pretending to be a cook in a sting operation.
See Fowler's article for the more specifics about fakes vs stubs vs mocks vs dummies, but for now, let's focus on a mock cook.
-----------------------
| |
v |
mock cook <- waiter <- test driver
A big part of unit testing the waiter component focuses on how the waiter interacts with the cook component . A mock-based approach focuses on fully specifying what the correct interaction is and detecting when it goes awry.
The mock object knows in advance what is supposed to happen during the test (e.g. which of its methods calls will be invoked, etc.) and the mock object knows how it is supposed to react (e.g. what return value to provide). The mock will indicate whether what really happens differs from what is supposed to happen. A custom mock object could be coded for the expected behavior of each test case, but a mocking framework strives to allow such a behavior specification to be clearly and easily indicated directly in the test case.
The conversation surrounding a mock-based test might look like this:
test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response
test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hot dog please
mock cook to waiter: order up: 1 hot dog ready (gives dummy hot dog to waiter)
waiter to test driver: here is your hot dog (gives dummy hot dog to test driver)test driver: TEST SUCCEEDED!
But since our waiter is new, this is what could happen:
test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response
test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hamburger please
mock cook stops the test: I was told to expect a hot dog order!test driver notes the problem: TEST FAILED! - the waiter changed the order
or
test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response
test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hot dog please
mock cook to waiter: order up: 1 hot dog ready (gives dummy hot dog to waiter)
waiter to test driver: here is your french fries (gives french fries from some other order to test driver)test driver notes the unexpected french fries: TEST FAILED! the waiter gave back wrong dish
It may be hard to clearly see the difference between mock objects and stubs without a contrasting stub-based example to go with this, but this answer is way too long already :-)
Also note that this is a pretty simplistic example and that mocking frameworks allow for some pretty sophisticated specifications of expected behavior from components to support comprehensive tests. There's plenty of material on mock objects and mocking frameworks for more information.