EasyMock study notes

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.

Added by bnmng on Wed, 08 Dec 2021 01:54:17 +0200