In this recipe, we will write a simple test using JMockit that verifies the behavior of the system under test when an exception is thrown.
In order to profit from JMockit, you need to add it to your classpath. The following is the JMockit configuration for Gradle:
testCompile 'com.googlecode.jmockit:jmockit:1.7'
The following is how you can add JMockit to your classpath using Maven:
<dependency> <groupId>com.googlecode.jmockit</groupId> <artifactId>jmockit</artifactId> <version>1.7</version> <scope>test</scope> </dependency>
If you do not use @RunWith(JMockit.class)
, then you need to define the JMockit dependency before the JUnit one! Please refer to http://jmockit.googlecode.com/svn/trunk/www/gettingStarted.html for more information.
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 to transfer tax for [%s]%n", exception, person.getName()); return false; } return true; } }
In order to test the system using JMockit, you need to perform the following steps:
Expectations
instance for strict stubbing.NonStrictExpectations
instance for non-strict stubbing.NonStrictExpectations
for stubbing, then you can define your verification logic in the initialization block of the Verifications
instance. Otherwise, it's not needed since all verification takes place via the Expectations
instance.The following snippet depicts the aforementioned scenario for JUnit:
@RunWith(JMockit.class) public class TaxTransfererTest { @Test public void should_return_false_when_tax_was_not_transfered_and_connection_to_irs_was_refused(@Mocked final TaxService taxService) { // given TaxTransferer systemUnderTest = new TaxTransferer(taxService); final Person person = new Person(); new NonStrictExpectations() { { taxService.hasAlreadyTransferredTax(person); result = false; taxService.transferTaxFor(person); result = new RuntimeException("Connection refused"); } }; // when boolean transferSuccessful = systemUnderTest.transferTaxFor(person); // then then(transferSuccessful).isFalse(); new Verifications() { { taxService.hasAlreadyTransferredTax(person); taxService.transferTaxFor(person); } }; } }
To use JMockit with TestNG, you just need to replace @RunWith(JMockit.class)
from the JUnit example with @Listeners(mockit.integration.testng.Initializer.class)
.
We will not discuss how JMockit works internally, but focus on what happens in the test itself, and what JMockit's approach is.
JMockit's approach regarding mocks is such the stubbing occurs via the code block inside the implementation of the Expectations
or NonStrictExpectations
class. Each line executed by the mocked instance followed by the assignment to the result
variable leads to the stubbing of the aforementioned call.
The explicit verification occurs in the code block inside the implementation of the Verifications
class. Since we use the NonStrictExpectations
class, we need to perform that verification through the Verifications
instance to verify our mock's behavior. If we used the Expectations
block, then the stubbing gets automatically verified.
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("Connectionrefused")).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 are as follows:
3.145.75.217