introduce
EasyMock is mainly used to facilitate the use of objects that can simulate the execution results of methods when writing unit tests, guide the execution of unit tests to the concerned code, and judge the execution results.
Introduce dependency
maven mode:
<dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>4.2</version> <scope>test</scope> </dependency>
You can also download the independent jar package easymock-4.2.jar and put it under the classpath. If you need to mock the class in the test, you can introduce Objenesis into the classpath.
Easymock version 3.2 has added Android support, which requires additional dependencies:
<dependency> <groupId>org.droidparts.dexmaker</groupId> <artifactId>dexmaker</artifactId> <version>1.5</version> </dependency>
Mock object
You can use the mock method to mock objects and introduce static methods:
import static org.easymock.EasyMock.*;
@Before public void setUp() { mock = mock(Collaborator.class); // 1 classUnderTest = new ClassUnderTest(); classUnderTest.setListener(mock); } @Test public void testRemoveNonExistingDocument() { // 2 (we do not expect anything) replay(mock); // 3 classUnderTest.removeDocument("Does not exist"); }
Above easymock version 3.2, you can also use the annotation @ mock to inject, and use the annotation @ TestSubject to indicate which test object the mock object is injected into
@RunWith(EasyMockRunner.class) public class ExampleTest { @TestSubject private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2 @Mock private Collaborator mock; // 1 @Test public void testRemoveNonExistingDocument() { replay(mock); classUnderTest.removeDocument("Does not exist"); } }
If @ RunWith supporting Junit unit testing is not EasyMockRunner.class in EasyMock3.3 or above, use @ Rule to enable EasyMock
public class ExampleTest { @Rule public EasyMockRule mocks = new EasyMockRule(this); @TestSubject private ClassUnderTest classUnderTest = new ClassUnderTest(); @Mock private Collaborator mock; @Test public void testRemoveNonExistingDocument() { replay(mock); classUnderTest.removeDocument("Does not exist"); } }
EasyMock4.1 and above also support the Extension mode of JUnit 5.
@ExtendWith(EasyMockExtension.class) public class ExampleTest { @TestSubject private ClassUnderTest classUnderTest = new ClassUnderTest(); @Mock private Collaborator mock; @Test public void testRemoveNonExistingDocument() { replay(mock); classUnderTest.removeDocument("Does not exist"); } }
Sometimes two Mock objects of the same type need to be injected into different objects. You can create objects with multiple @ Mock annotations. The annotation supports the name attribute to set the name of the Mock object and the fieldName to set the attribute to be injected. Type indicates whether the type of the Mock object is NICE or STRICT (STRICT mode will verify the order of method calls)
@Mock(type = MockType.NICE, name = "mock", fieldName = "someField") private Collaborator mock; @Mock(type = MockType.STRICT, name = "anotherMock", fieldName = "someOtherField") private Collaborator anotherMock;
EasyMockSupport can automatically register, replay, reset or verify in batches without calling them one by one
The test class can be inherited or used as a member. If it is used as an inherited class, the mock, replayAll and verifyAll methods of the parent class can be called directly. If it is used as a member, the above methods of this member variable can be called.
Strict Mock and Nick Mock
For mock objects created in strict mode, the default method is to throw an exception. When a method without mock is called, an exception will be thrown.
Nice Mock mode. The default method is to return the default value of the method definition type.
Mock partial method
Some methods are simulated, and others that are not simulated will maintain their original behavior
ToMock mock = partialMockBuilder(ToMock.class) .addMockedMethod("mockedMethod").createMock();
Object whose Mock constructor requires parameters
By default, a no parameter constructor is used to create mock objects, but some objects need to pass some parameters to the constructor to create objects, so you can use a writing method similar to the following:
ToMock mock = partialMockBuilder(ToMock.class) .withConstructor(1, 2, 3); // 1, 2, 3 are the constructor parameters
Override default constructor
DefaultClassInstantiator is used by default. It works well for serializable classes and other situations where you can guess the best constructor and parameters.
However, if you want to implement a constructor yourself, you can implement the iclassinstator interface and use classinstantiarfactory. Setinstantiator() to set a custom constructor. If you want to restore the default constructor, you can call setDefaultInstantiator()
Note: the constructor is a static object, so it is common among multiple tests. Make sure to reset the state when necessary.
Limitations of class simulation
- For consistency, the equals(), toString(), hashCode() and finalize() methods have a set of internal behaviors during class simulation and cannot be overridden.
- The final method cannot be mock. If the final method is called, the original code will be executed
- private methods cannot be mock. If they are called, the original code will be entertained.
- In some cases, if your test calls private methods, you should note that these private methods are not mock
- Objenesis is used to instantiate the class, and the list of supported JVM s is here here
Named mock object
Mock objects can be named when they are created, ` mock (string name, class < T > tomock), strictmock (string name, class < T > tomock) or nicemock (string name, class < T > tomock). The names will be seen when exceptions occur.