Stubbing methods so that they call real methods

In this recipe, we will stub a method that returns a value so that it calls a real method. This way, we will construct a partial mock (to read more about partial mocking, please refer to Chapter 2, Creating Mocks).

Getting ready

For this recipe, our system under test will be MeanTaxFactorCalculator, which calls TaxFactorFetcher twice to get a tax factor for the given person and then calculates a mean value for those two results as follows:

public class MeanTaxFactorCalculator {

    private final TaxFactorFetcher taxFactorFetcher;

    public MeanTaxFactorCalculator(TaxFactorFetcher taxFactorFetcher) {
        this.taxFactorFetcher = taxFactorFetcher;
    }

    public double calculateMeanTaxFactorFor(Person person) {
        double taxFactor = taxFactorFetcher.getTaxFactorFor(person);
        double anotherTaxFactor = taxFactorFetcher.getTaxFactorFor(person);
        return (taxFactor + anotherTaxFactor) / 2;
    }

}

Unlike the previous recipes, TaxFactorFetcher will not be an interface but a concrete class.

How to do it...

To stub nonvoid methods so that they execute the logic from the custom answer, you have to perform the following steps:

  1. For the BDD approach, call BDDMockito.given(mock.methodToStub()).willCallRealMethod(), or in the standard way, call Mockito.when(mock.methodToStub()).thenCallRealMehod().
  2. Regardless of the chosen approach in the given(...) or when(...) method, you have to provide the mock's method call.
  3. Remember that the last passed value during the stubbing will be returned for each stubbed method call. In other words, say that you stub the mock as follows:
    given(taxFetcher.getTax()).willReturn(2). willCallRealMethod()

    Then, regardless of the number of taxFetcher.getTax() method executions, first 2 will be returned, and then you will always have the real logic executed (until it is stubbed again).

Now, let's move to the JUnit test. See Chapter 1, Getting Started with Mockito, for the TestNG configuration (remember that I'm using BDDMockito.given(...) and AssertJ's BDDAssertions.then(...) static methods. Check out Chapter 7, Verifying Behavior with Object Matchers, for more details on how to work with AssertJ or how to do the same with Hamcrest's assertThat(...)):

@RunWith(MockitoJUnitRunner.class)
public class MeanTaxFactorCalculatorTest {

    @Mock TaxService taxService;

    @InjectMocks MeanTaxFactorCalculator systemUnderTest;

    @Test
    public void should_return_mean_tax_factor() {
        // given
        double taxFactor = 15000;
        double expectedMeanTaxFactor = (TaxService.NO_COUNTRY_TAX_FACTOR + taxFactor) / 2;
        given(taxService.getTaxFactorFor(any(Person.class))).willCallRealMethod().willReturn(taxFactor);

        // when
        double meanTaxFactor = systemUnderTest.calculateMeanTaxFactorFor(new Person());

        // then
        then(meanTaxFactor).isEqualTo(expectedMeanTaxFactor);
    }

}

Note

Another thing to remember is that if you need to create a partial mock, and if you really don't have some strong arguments to back that decision up, then you should rethink the architecture of your program or your tests since it is not of the best quality, most likely.

It's always crucial to remember the boy scout rule and the process of refactoring. You should work on your code and the code of your colleagues in an iterative manner, trying to make small improvements each time you operate on it.

See also

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

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