Mockito
Stubbing
Bounded Wild-Cards
Java
Unit Testing

Mockito Stubbing Methods That Return Type With Bounded Wild-Cards

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Mockito is a widely used mocking framework for unit tests in Java applications. It allows developers to create mock objects, define their behavior, and specify interactions, thereby isolating the components under test. One of the features of Mockito is the ability to stub methods, which is essential for defining the output of method calls on mock objects. This article delves into the nuances of stubbing methods that return types with bounded wild-cards in Mockito.

Understanding Wild-Cards and Bounded Wild-Cards

Wild-Cards in Generics

Generics in Java introduce the concept of wild-cards, which are used to represent an unknown type. Wild-cards are specified using a question mark (?) and offer flexibility when working with parameterized classes and interfaces.

Bounded Wild-Cards

Bounded wild-cards restrict the types that a generic method or class can work with. Java supports two types of bounded wild-cards:

  • Upper-bounded wild-cards: Represented by <? extends T>, where T is a certain type. It signifies that the unknown type is a subtype of T.
  • Lower-bounded wild-cards: Represented by <? super T>, indicating that the unknown type is a supertype of T.

Stubbing Methods Returning Types with Bounded Wild-Cards

When using Mockito, stubbing methods that return bounded wild-cards can be slightly more complex than standard methods. Let's explore this with technical details and examples.

Example: Upper-Bounded Wild-Cards

Imagine a scenario where we have a generic class Container and a method that returns a list of items:

java
1public class Container<T> {
2    public List<? extends Number> getNumbers() {
3        // Implementation omitted
4        return null;
5    }
6}

Here's how we can stub the getNumbers method using Mockito:

java
1import org.mockito.Mockito;
2import java.util.Arrays;
3import java.util.List;
4
5public class Example {
6    public static void main(String[] args) {
7        // Creating a mock of the Container class
8        Container<?> mockContainer = Mockito.mock(Container.class);
9        
10        // Defining a stub for getNumbers
11        List<? extends Number> numbers = Arrays.asList(1, 2.5, 3L);
12        Mockito.when(mockContainer.getNumbers()).thenReturn(numbers);
13        
14        // The method returns the stubbed list
15        List<? extends Number> result = mockContainer.getNumbers();
16        System.out.println(result); // Output: [1, 2.5, 3]
17    }
18}

In this example, the getNumbers method is stubbed to return a list containing an Integer, a Double, and a Long. This exemplifies an upper-bounded wild-card where the return list can include any subtype of Number.

Example: Lower-Bounded Wild-Cards

Consider a situation with lower-bounded wild-cards:

java
1public class Processor {
2    public void processItems(List<? super Integer> items) {
3        // Implementation omitted
4    }
5}

Stubbing the method might differ because lower-bounded wild-cards are typically used as method parameters instead of return types. Here's how this would be interacted with in a test context:

java
1import org.mockito.Mockito;
2import java.util.ArrayList;
3import java.util.List;
4
5public class LowerBoundExample {
6    public static void main(String[] args) {
7        // Create a mock Processor instance
8        Processor mockProcessor = Mockito.mock(Processor.class);
9        
10        // Create a list that can accept integers
11        List<Number> items = new ArrayList<>();
12        
13        // Use doNothing for methods that return void
14        Mockito.doNothing().when(mockProcessor).processItems(items);
15        
16        // Calling the mocked method for demonstration
17        mockProcessor.processItems(items);
18        System.out.println("Items processed.");
19    }
20}

In this case, the processItems method is configured to accept a list of Number instances, which is compatible with Integer.

Practical Tips and Key Points

  • Type Safety: Generics and wild-cards in Java enforce compile-time type safety. Be sure to honor these constraints when stubbing methods.
  • Mockito's Limitations: Mockito does not allow creating mocks of primitive types or final classes due to Java's type system and the limitations of proxies.
  • Flexibility with Spy: If you need to stub part of a method's functionality while preserving the original behavior, consider using Mockito.spy().

Summary Table

ConceptExplanation
Wild-CardsRepresent unknown types in generics using ?.
Upper-Bounded Wild-Cards<? extends T>: Represents a subtype of T.
Lower-Bounded Wild-Cards<? super T>: Represents a supertype of T.
Stubbing SyntaxMockito.when(...) for methods returning values, Mockito.doNothing() for void methods.
Mocking LimitationsCannot mock final classes or enums.

Conclusion

Stubbing methods in Mockito that return types with bounded wild-cards is a powerful feature but requires a solid understanding of Java's generics system. This tutorial should provide a foundation for effectively using Mockito in scenarios involving such complex types. By leveraging the strengths of generics, developers create cleaner, more maintainable code. Keep exploring the rich feature set of Mockito to enhance your unit testing strategy.


Course illustration
Course illustration

All Rights Reserved.