Mockito versus JMockit

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.

Getting ready

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>            

Note

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;
  }

}

How to do it...

In order to test the system using JMockit, you need to perform the following steps:

  1. Create mocks by passing them as the test method's parameters.
  2. Stub the mock's behavior in the initialization block.
  3. Stub Expectations instance for strict stubbing.
  4. Stub NonStrictExpectations instance for non-strict stubbing.
  5. Execute the logic of the system under test.
  6. Assert the behavior of the system under test.
  7. If you used 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);
        }
        };
    }

}

Note

JMockit integrates very nicely with JUnit. You need to annotate your test class with @RunWith(JMockit.class). Only then can you profit from the @Mock annotation that you can place as an argument of the test method.

To use JMockit with TestNG, you just need to replace @RunWith(JMockit.class) from the JUnit example with @Listeners(mockit.integration.testng.Initializer.class).

How it works...

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.

There's more...

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:

  • The possibility of having no explicit record or replay of the mock's methods (only possible through stubbing with NonStrictExpectations)
  • The possibility of explicit verification (via the Verifications instance)

The primary differences are as follows:

  • JMockit contains functionalities more similar to PowerMock than Mockito (it can stub object instantiation and final and static methods)
  • JMockit supports strict mocks
  • JMockit has a built-in coverage report
  • Stubbing and verifying through the code block during code implementation

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.150.123