1. Mock Object
2. the MockObject framework
3. Mock tools
What is the Holy Grail of TDD? What do you strive for when you write test?
- focused tests: ideally one assert each
- independent tests: the fixture is built and cleaned up for each test, allowing tests to run in any order
- fast tests: you want to be able to run them frequently
1. Mock Object
- Take the place of real objects for the purposes of testing some functionality that interacts with and is dependent on the real objects.
- Basic concept
- To create lightweight, controllable replacements for objects you need in order to write your tests.
- It can enable you to specify and test your code's interaction with the mocks themselves.
- Why to use mocks?
- Uses for mock objects
- To help keep the design decoupled.
- To check your code's usage of another object.
- To test-drive your code from the inside out.
- To make your tests run faster.
- To make it easier to develop code that interacts with hardware devices, remote systems, and other problematic resources.
- To defer having to implement a class.
- To let us test-drive components in isolation from the rest of the system.
- To promote interface-based design.
- To encourage composition over inheritance.
- To refine interfaces.
- To test unusual, unlikely, and exceptional situations.
2. the MockObject framework
The MockObjects project is a generic framework.
Goal: To facilitate developing programmer tests in the mock style.
Verifiable provides an interface for classes that can be asked at the end of a test to confirm that the correct behavior occurred. As shown in the diagram, it is the root of the core of the framework.
MockObject is extended by mocks created with the framework. Its purpose is primarily to provide some convenience methods.
ReturnObjectList is used to contain an ordered sequence of objects that can be sequenced through. When the next object is requested, an assertion error will be thrown if there are no more objects. ReturnObjectList implements Verifiable and its verify() method throws an assertion error if there are any objects remaining.
This class can be used to manage a list of return values that are to be returned by successive calls to a given method in a mock.
Expectation is another interface that extends Verifiable. Its purpose is to provide an interface for classes that have the notion of expecting certain things to happen. The verify() method of an Expectation will check that the expectation was fulfilled. The following classes are concrete implementations that embody specific types of expectations.
AbstractExpectation provides a superclass for specific kinds of expectations. Expectations can be named. There is also support for choosing when failure due to expectation violation occurs: either as soon as the actual situation is known (this is the default behavior) or when it is asked to verify.
ExpectationValue is used to set up a value expectation. When created, you set an expected value, and later (in response to calls by the class being tested) the actual value is set. Verification consists of checking for equality (using assertEquals())of the expected and actual values.
This class is often used to capture expectations of argument values.
ExpectationDoubleValue is similar in purpose to ExpectationValue, except that it works with double values. The notable difference is that setExpected() takes an additional double argument that specifies the acceptable error when comparing the expected and actual double values.
ExpectationSegment is used for substring expectations. That is, you expect that the actual value contains a certain string.
Verification for this expectation checks that the expected string is a substring of the actual string.
ExpectationCounter lets you set up an expectation that something (e.g., a method call) should happen a specific number of times. You set it up with the expected count, increment it as required, and verify that the count was, in fact, as expected. If this expectation is set to fail immediately upon violation of the expectation, it will fail when incremented past the expected value.
ExpectationCollection provides an interface for classes that support multiple expected-actual value pairs.
Methods are defined to add expected and actual values, singly and in multiples as arrays, enumerations, and iterators.
AbstractExpectationCollection provides default implementations for the required methods (from the implemented interfaces). It also provides abstract accessors for the collections of expected and actual values.
ExpectationList is an implementation of AbstractExpectationCollection that uses two instances of ArrayList for storing expected and actual values. It is used when the order of the pairs is relevant.
ExpectationSet is another implementation of AbstractExpectationCollection that uses two instances of HashSet for storing expected and actual values. It is used when the order of the pairs is irrelevant.
ExpectationMap is used to manage expectations involving named or indexed values. It uses an ExpectationSet to manage the expected keys.
A common pattern to use mocks:
- Create the mocks
- Set state and expectations
- Execute the code you are test-driving using the mocks
- Have the mocks verify that expectations were met
3. Mock tools
MockMaker is a tool for creating mock classes form a given interface or class.
MockMaker builds mock classes using the MockObjects framework.
MockMaker is a program for creating source code for mock object classes. Given an interface, it writes the source code for a mock object class that implements the interface and allows instances of that class to have expectations set about how many times a method is called, what parameters each method is called with, and to pre-set return values for methods. In many cases (possibly most cases), the classes produced by MockMaker are exactly what you want a mock class to do.
EasyMock is a framework for creating mock objects dynamically at runtime.
EasyMock provides Mock Objects for interfaces (and objects through the class extension) by generating them on the fly using Java's proxy mechanism. Due to EasyMock's unique style of recording expectations, most refactorings will not affect the Mock Objects. So EasyMock is a perfect fit for Test-Driven Development.
Unit testing is the testing of software units in isolation. However, most units do not work alone, but they collaborate with other units. To test a unit in isolation, we have to simulate the collaborators in the test.
A Mock Object is a test-oriented replacement for a collaborator. It is configured to simulate the object that it replaces in a simple way. In contrast to a stub, a Mock Object also verifies whether it is used as expected.
Mock objects can, indeed, provide a way to achieve the three goals.
- Focused tests
- Independent tests
- Fast tests
- Stubs: a class with methods that do nothing. They simply are there to allow the system to compile and run.
- Fakes: a class with methods that return a fixed value or values that can either be hardcoded or set programmatically.
- Mocks: a class in which you can set expectations regarding what methods are calls, with what parameters, how often, etc. you can also set return values for various calling situations. A mock will also provide a way to verify that the expectations were met.
Technorati 标签: 单元测试；Mock Objects