Stubbing methods so that they return custom answers

In this recipe, we will stub a method that returns a value so that it returns a custom answer of our choice.

Getting ready

For this recipe, our system under test will again 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;
    }

}

Let's assume that depending on whether the person is from a defined or undefined country, the logic of calculating the factor by TaxFactorFetcher is different.

How to do it...

To stub nonvoid methods so 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()).willAnswer(answer), or in the standard way, call Mockito.when(mock.methodToStub()).thenAnswer(answer).
  2. Regardless of the chosen approach in the given(...) or when(...) method, you have to provide the mock's method call, and in willAnswer(...) or thenAnswer(...), you have to provide the desired Answer implementation.
  3. Remember that the last passed value during the stubbing will be returned for each stubbed method call. In other words, you stub the mock as follows:
    given(taxFetcher.getTax()).willAnswer(new Answer1(), new Answer2());

    Then, regardless of the number of taxFetcher.getTax() method executions, first Answer1 will be executed, and then you will always have Answer2 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, to learn how to work with AssertJ or how to do the same with Hamcrest's assertThat(...)):

@RunWith(MockitoJUnitRunner.class)
public class MeanTaxFactorCalculatorTest {

    @Mock TaxFactorFetcher taxFactorFetcher;

    @InjectMocks MeanTaxFactorCalculator systemUnderTest;

    @Test
    public void should_return_tax_factor_incremented_by_additional_factor_when_calculating_mean_tax_factor() {
        // given
      final double additionalTaxFactor = 100;
      final double factorForPersonFromUndefinedCountry = 200;
      given(taxFactorFetcher.getTaxFactorFor(any(Person.class))).willAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                if (invocation.getArguments().length > 0) {
                    Person person = (Person) invocation.getArguments()[0];
                    if (!person.isCountryDefined()) {
                        return additionalTaxFactor + factorForPersonFromUndefinedCountry;
                    }
                }
                return additionalTaxFactor;
            }
        });

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

        // then
        then(meanTaxFactor).isEqualTo(additionalTaxFactor + factorForPersonFromUndefinedCountry);
    }

}

Note

Another thing to remember is that most likely, you won't have the need to create any special answers. If that is the case, it's highly probable that your scenario is getting too complicated. For additional information regarding Answers, please refer to Chapter 2, Creating Mocks.

How it works...

Please refer to the Stubbing methods that return values recipe for more information on the Mockito internals related to stubbing methods so that they throw exceptions.

It's worth mentioning that eventually, when the willThrow(...) or thenThrow(...) code is called, Mockito constructs the ThrowsException answer with the passed exception and then delegates further execution to it.

There's more...

Mockito provides a series of possible answers to be executed either by using the fluent interface API, or by means of varargs.

You can perform stubbing via a fluent API as follows:

given(...).willAnswer(answer1).willAnswer(answer2)...willAnswer(answer3)

Or, with the varargs style, you can perform the stubbing as follows:

given(...).willAnswer(answer1, answer2, …. answerN)

Please refer to the There's more... section of the Stubbing methods so that they throw exception recipe from this chapter for analogous test examples.

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.16.139.8