Search

Dark theme | Light theme
Showing posts with label Mockito. Show all posts
Showing posts with label Mockito. Show all posts

March 25, 2024

Mastering Mockito: Returning Fresh Stream For Multiple Calls To Mocked Method

When we mock a method that returns a Stream we need to make sure we return a fresh Stream on each invocation to support multiple calls to the mocked method. If we don’t do that, the stream will be closed after the first call and subsequent calls will throw exceptions. We can chain multiple thenReturn calls to return a fresh Stream each time the mocked method is invoked. Or we can use multiple arguments with the thenReturn method, where each argument is returned based on the number of times the mocked method is invoked. So on the first invocation the first argument is returned, on second invocation the second argument and so on. This works when we know the exact number of invocations in advance. But if we want to be more flexible and want to support any number of invocations, then we can use thenAnswer method. This method needs an Answer implementation that returns a value on each invocation. The Answer interface is a functional interface with only one method that needs to be implemented. We can rely on a function call to implement the Answer interface where the function gets a InvocationOnMock object as parameter and returns a value. As the function is called each time the mocked method is invoked, we can return a Stream that will be new each time.

In the following example we use chained method calls using thenReturn and we use thenAnwer to support multiple calls to our mocked method temperature that returns a Stream of Double values:

package mrhaki;

import org.junit.jupiter.api.Test;

import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MockReturnMultipleStreams {

    // Simple interface to return a stream of
    // temperature values for a given city.
    interface Weather {
        Stream<Double> temperature(String city);
    }

    // Simple class that uses Weather interface.
    static class SubjectUnderTest {

        private final Weather weather;

        SubjectUnderTest(Weather weather) {this.weather = weather;}

        public String weatherReport(String city) {
            // By invoking the methods celcius and fahrenheit we will
            // invoke the weather.temperature method twice.
            return String.format("The temperature in %s is %.1f degrees Celcius or %.1f degrees Fahrenheit.",
                                 city, celcius(city), fahrenheit(city));
        }

        private double celcius(String city) {
            return weather.temperature(city).findAny().get();
        }

        private double fahrenheit(String city) {
            return (celcius(city) * 9/5)  + 32;
        }
    }

    private final Weather weather = mock(Weather.class);
    private final SubjectUnderTest subjectUnderTest = new SubjectUnderTest(weather);

    @Test
    void shouldReturnCorrectWeatherReport() {
        // given

        // Return type of the mocked method temperature is a Stream.
        // On the first call in the subjectUnderTest instance the stream
        // is closed, so the second call will give an exception that
        // the stream is already been operated upon or closed.
        // To support the second call we need to return a new stream
        // with the same content.
        // If we need to support more calls than two we need
        // to add more thenReturn statements.
        // See the next test method for an example with thenAnswer
        // that supports multiple calls more easily.
        double temperature = 21.0;
        when(weather.temperature("Tilburg"))
                // First call
                .thenReturn(Stream.of(temperature))
                // Second call
                .thenReturn(Stream.of(temperature));

        // Alternative syntax:
        // when(weather.temperature("Tilburg"))
        //        .thenReturn(Stream.of(temperature), Stream.of(temperature));

        // when
        String result = subjectUnderTest.weatherReport("Tilburg");

        // then
        assertThat(result).isEqualTo("The temperature in Tilburg is 21,0 degrees Celcius or 69,8 degrees Fahrenheit.");
    }

    @Test
    void shouldReturnCorrectWeatherReport2() {
        // given

        // Return type of the mocked method temperature is a Stream.
        // On the first call in the subjectUnderTest instance the stream
        // is closed, so the second call will give an exception that
        // the stream is already been operated upon or closed.
        // To support the second call we can use thenAnswer method
        // which will return a fresh Stream on each call.
        // Now the number of calls is not limited, because on each
        // invocation a fresh Stream is created.
        when(weather.temperature("Tilburg"))
                .thenAnswer(invocationOnMock -> Stream.of(21.0));

        // when
        String result = subjectUnderTest.weatherReport("Tilburg");

        // then
        assertThat(result).isEqualTo("The temperature in Tilburg is 21,0 degrees Celcius or 69,8 degrees Fahrenheit.");
    }
}

Written with Mockito 3.12.4.

May 17, 2013

Spocklight: Change Return Value of Mocked or Stubbed Service Based On Argument Value

My colleague Albert van Veen wrote a blog post about Using ArgumentMatchers with Mockito. The idea is to let a mocked or stubbed service return a different value based on the argument passed into the service. This is inspired me to write the same sample with Spock.

Spock already has built-in mock and stub support, so first of all we don’t need an extra library to support mocking and stubbing. We can easily create a mock or stub with the Mock() and Stub() methods. We will see usage of both in the following examples.

In the first example we simply return true or false for ChocolateService.doesCustomerLikesChocolate() in the separate test methods.

import spock.lang.*

public class CandyServiceSpecification extends Specification {

    private ChocolateService chocolateService = Mock()
    private CandyService candyService = new CandyServiceImpl()
 
    def setup() {
        candyService.chocolateService = chocolateService
    }

    def "Customer Albert really likes chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Albert')

        and: 'Mock returns true'
        1 * chocolateService.doesCustomerLikesChocolate(customer) >> true
        
        expect: 'Albert likes chocolate'
        candyService.getCandiesLikeByCustomer(customer).contains Candy.CHOCOLATE
    }

    def "Other customer do not like chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Any other firstname')

        and: 'Mock returns false'
        1 * chocolateService.doesCustomerLikesChocolate(customer) >> false
        
        expect: 'Customer does not like chocolate'
        !candyService.getCandiesLikeByCustomer(customer).contains(Candy.CHOCOLATE)
    }

}

In the following example we mimic the ArgumentMatcher and this time we use a stub instead of mock.

import spock.lang.*

public class CandyServiceSpecification extends Specification {

    private CandyService candyService = new CandyServiceImpl()
 
    def setup() {
        candyService.chocolateService = Stub(ChocolateService) {
            getCandiesLikeByCustomer(_) >> { Customer customer ->
                customer?.firstName == 'Albert'
            }
        }
    }

    def "Customer Albert really likes chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Albert')
        
        expect: 'Albert likes chocolate'
        candyService.getCandiesLikeByCustomer(customer).contains Candy.CHOCOLATE
    }

    def "Other customer do not like chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Any other firstname')
        
        expect: 'Customer does not like chocolate'
        !candyService.getCandiesLikeByCustomer(customer).contains(Candy.CHOCOLATE)
    }

}

Code written with Spock 0.7-groovy-2.0

September 15, 2010

Private Spring Dependency Injections for Unit Testing

If we want to unit test a Spring managed bean with a private field that is annotated with for example the @Autowired annotation, we must do something special. Normally we cannot access the private field to assign for example a stub implementation for testing, because we have to use the public setter method. But Spring allows the use of the @Autowired annotation on a private field. And that means we don't have a public setter method. We must use org.springframework.test.util.ReflectionTestUtils.setField() to assign a new value to the field. We pass the object which contains the private field, the field name and value to the method and our value is assigned to the private variable. So we can use this method to assign a stub implementation to the field and use it for testing.

// Class to test: src/main/java/com/mrhaki/spring/MyService.java
package com.mrhaki.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    @Autowired
    private MessageService messageService;

    public String say(String name) {
        return messageService.getMessage() + name;
    }
}
// Support class used in MyService: src/main/java/com/mrhaki/spring/MessageService.java
package com.mrhaki.spring;

import org.springframework.stereotype.Component;

@Component
public class MessageService {
    public String getMessage() {
        return "Hello, ";
    }
}

We want to unit test MyService and provide a mock implementation for MessageService, so we only test the code in MyService. We use Mockito to provide the mock functionality. And because messageService is a private field we must use ReflectionTestUtils.setField() method.

// Test class for testing MyService: src/test/java/com/mrhaki/spring/MyServiceTest.java
package com.mrhaki.spring;

import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MyServiceTest {
    @Test
    public void sayHi() {
        MessageService messageService = mock(MessageService.class);
        when(messageService.getMessage()).thenReturn("Hi, ");

        MyService myService = new MyService();
        // Inject mock into private field:
        ReflectionTestUtils.setField(myService, "messageService", messageService);

        assertEquals("Hi, mrhaki", myService.say("mrhaki"));
    }
}

As a bonus we can use the following Gradle build script to compile and test these classes:

apply plugin: 'java'

repositories {
  mavenCentral()
}

dependencies {
  compile 'org.springframework:spring-context:3.0.4.RELEASE'
  testCompile 'junit:junit:4.8.1', 'org.mockito:mockito-all:1.8.5', 'org.springframework:spring-test:3.0.4.RELEASE'
}

Project is also available on GitHub: BlogSamples/SpringTestInjection.