In this recipe, we will write a simple test using EasyMock that verifies the behavior of the system under test when an exception is thrown.
In order to profit from EasyMock, you need to add it to your classpath. This is the configuration for Gradle:
testCompile 'org.easymock:easymock:3.2'
The following is how you add the EasyMock dependency in Maven:
<dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.2</version> <scope>test</scope> </dependency>
Let's assume that our system under test is the tax transferring system for a given person, as shown in the following code:
public class TaxTransferer { private final TaxService taxService; public TaxTransferer(TaxService taxService) { this.taxService = taxService; } public boolean transferTaxFor(Person person) { if (taxService.hasAlreadyTransferredTax(person)) { return false; } try { taxService.transferTaxFor(person); } catch (Exception exception) { System.out.printf("Exception [%s] caught while trying totransfer tax for [%s]%n", exception, person.getName()); return false; } return true; } }
In order to test the system using EasyMock, you need to perform the following steps:
The following is an example of a JUnit test with EasyMock:
@RunWith(EasyMockRunner.class) public class TaxTransfererTest { @Mock TaxService taxService; TaxTransferer systemUnderTest; @Test public void should_return_false_when_tax_was_not_transfered_and_connection_to_irs_was_refused() { // expect systemUnderTest = new TaxTransferer(taxService); Person person = new Person(); expect(taxService.hasAlreadyTransferredTax(anyObject(Person.class))).andReturn(false); taxService.transferTaxFor(same(person)); expectLastCall().andStubThrow(new RuntimeException("Connection refused")); replay(taxService); // act boolean transferSuccessful = systemUnderTest.transferTaxFor(person); // assert then(transferSuccessful).isFalse(); verify(taxService); } }
EasyMock integrates very nicely with JUnit. You need to annotate your test class with @RunWith(EasyMockRunner.class)
. Only then can you profit from the @Mock
annotation that will create the mock for you; @TestSubject
will inject proper mocks for you. Unfortunately, as you can see in our example, our system under test wasn't annotated with @TestSubject
. That's because TaxTransferer
fields are final and we inject their collaborators via constructor. EasyMock doesn't support constructor injection, it only supports field injection. This is why we need to inject the collaborator manually.
The following is how you can integrate EasyMock with TestNG:
public class TaxTransfererTestNgTest { @Mock TaxService taxService; TaxTransferer systemUnderTest; @BeforeMethod public void setup() { EasyMockSupport.injectMocks(this); systemUnderTest = new TaxTransferer(taxService); } @Test public void should_return_false_when_tax_was_not_transfered_and_connection_to_irs_was_refused() { // expect Person person = new Person(); expect(taxService.hasAlreadyTransferredTax(anyObject(Person.class))).andReturn(false); taxService.transferTaxFor(same(person)); expectLastCall().andStubThrow(new RuntimeException("Connection refused")); replay(taxService); // act boolean transferSuccessful = systemUnderTest.transferTaxFor(person); // assert then(transferSuccessful).isFalse(); verify(taxService); } }
We will not discuss how EasyMock works internally, but focus on what happens in the test itself, and what the EasyMock approach is. EasyMock's approach towards mocks is captured in the following steps:
replay(T mock)
static method). Afterwards, you can act and assert the results.As for stubbing, you can call the static expect(T mock)
method to stub a method execution that returns a value. To stub void methods, you need to first execute the void method and then call the static expectLastCall()
method. Only then can you define exactly how the mock should behave.
Mockito's test code of the system would look like the following (example for JUnit):
@RunWith(MockitoJUnitRunner.class) public class TaxTransfererTest { @Mock TaxService taxService; @InjectMocks TaxTransferer systemUnderTest; @Test public void should_return_false_when_tax_was_not_transfered_and_connection_to_irs_was_refused() { // given Person person = new Person(); given(taxService.hasAlreadyTransferredTax(person)).willReturn(false); willThrow(new TaxServiceConnectionException("Connection refused")).given(taxService).transferTaxFor(person); // when boolean transferSuccessful = systemUnderTest.transferTaxFor(person); // then then(transferSuccessful).isFalse(); verify(taxService).hasAlreadyTransferredTax(person); verify(taxService).transferTaxFor(person); } }
The primary similarities between EasyMock and Mockito are as follows:
The primary differences between EasyMock and Mockito are as follows:
verify()
method.collaborator.execute(mutate(object)); collaborator.execute(mutate(object));
In EasyMock, since you define expectations at the beginning, you are able to verify the value of the argument of the execute(…)
method at each step. In Mockito, you will only be able to check that at the second execution, thus having inOrder.verify(mockedCollaborator).execute(objectAtStep1());
and inOrder.verify(mockedCollaborator).execute(objectAtStep2());
would make only the second line pass whereas the first would fail. EasyMock's way to test it would be as follows:
mockedCollaborator.execute(mutate(object)); mockedCollaborator.execute(mutate(object)); replay(mockedCollaborator);
3.135.188.121