@MockBean Example in Spring Test
April 20, 2021
On this page we will learn using @MockBean
annotation in Spring Boot unit test cases. Let us understand @MockBean
point-by-point.
1. The
@MockBean
is a Spring Boot test annotation that is used to add mocks to ApplicationContext
.
2. A mock will replace existing bean of the same type defined in the context and if no existing bean then new one will be added to context.
3. The
@MockBean
can be used at field level and class level in unit test classes. The @MockBean
can also be used in @Configuration
classes.
4. Mocks can be registered by type or bean name.
5. If a registered bean in application context is mocked then injection of this bean on field is also mocked.
6. The test class using
@MockBean
, is annotated with
@RunWith(SpringRunner.class)
@ExtendWith(SpringExtension.class)
7. The
@MockBean
has following attributes.
answer: The
org.mockito.Answers
type to use on the mock.
classes: Classes to mock.
extraInterfaces: Extra interfaces to be declared on the mock.
name: Name of the bean to register.
reset: The
MockReset
mode.
serializable: Boolean if generated mock is serializable.
value: Alias of
classes
i.e. the classes to mock.
Contents
Technologies Used
Find the technologies being used in our example.1. Java 14
2. Spring 5.3.6
3. Spring Boot 2.4.5
4. JUnit 5.7.1
5. Mockito 3.6.28
6. Maven 3.8.1
Maven Dependencies
Find the Maven dependencies.pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.5</version> </parent> <properties> <context.path>spring-app</context.path> <java.version>14</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.7.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.7.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-params</artifactId> <version>5.7.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-launcher</artifactId> <version>1.7.1</version> <scope>test</scope> </dependency> </dependencies>
Mock at Field Level
Here we will use@MockBean
at field level. In this case @Autowired
will not be annotated for dependency injection.
MyAppTest1.java
package com.concretepage; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import com.concretepage.config.AppConfig; import com.concretepage.service.MyService1; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = AppConfig.class) public class MyAppTest1 { @MockBean private MyService1 myService; @Test public void testApp1() { Mockito.when(myService.getMessage()).thenReturn("Welcome"); String msg = myService.getMessage(); assertEquals("Welcome", msg); } }
getMessage()
method of MyService1
class has been mocked.
If a service class is using a bean which has been mocked, then that service will receive mocked bean in our test class.
MyAppTest1.java
@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = AppConfig.class) public class MyAppTest1 { @MockBean private MyService1 myService1; @MockBean private MyService2 myService2; @Autowired private UserService userService; @Test public void testApp1() { Mockito.when(myService1.getMessage()).thenReturn("Welcome"); String msg = myService1.getMessage(); assertEquals("Welcome", msg); } @Test public void testApp2() { Mockito.when(myService2.getCount()).thenReturn(100); int count = userService.getUserCount(); assertEquals(100, count); } }
getCount()
method of MyService2
has been mocked to return 100. The getCount()
is being called by getUserCount()
of UserService
. In the test result, we can see that getUserCount()
will call mocked getCount()
method.
Find the classes used in our unit test class.
MyService1.java
@Service public class MyService1 { public String getMessage() { return "Hello World!"; } }
@Service public class MyService2 { public int getCount() { return 50; } }
@Service public class UserService { @Autowired MyService2 myService; public int getUserCount() { return myService.getCount(); } }
Mock at Class Level
The@MockBean
has attributes classes
and value
. The value
is the alias of classes
. We annotate test class with @MockBean
and configure classes to it.
More than one classes at class level, are configured in following ways.
1. Using
value
attribute.
@ExtendWith(SpringExtension.class) @MockBean({MyService1.class, MyService2.class}) public class MyAppTest2 { ------ }
@MockBean
.
@ExtendWith(SpringExtension.class) @MockBean(MyService1.class) @MockBean(MyService2.class) public class MyAppTest2 { ------ }
@MockBeans
. The @MockBeans
is the container annotation that aggregates several @MockBean
annotations.
@ExtendWith(SpringExtension.class) @MockBeans({ @MockBean(MyService1.class), @MockBean(MyService2.class) }) public class MyAppTest2 { ------ }
Find a complete test class with
@MockBean
annotated at class level.
MyAppTest2.java
@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = AppConfig.class) @MockBeans({ @MockBean(MyService1.class), @MockBean(MyService2.class) }) public class MyAppTest2 { @Autowired private MyService1 myService1; @Autowired private MyService2 myService2; @Test public void testApp1() { Mockito.when(myService1.getMessage()).thenReturn("Welcome"); String msg = myService1.getMessage(); assertEquals("Welcome", msg); } @Test public void testApp2() { Mockito.when(myService2.getCount()).thenReturn(100); int count = myService2.getCount(); assertEquals(100, count); } }
Mock using @Configuration
The classes can be mocked in a@Configuration
annotated class using @MockBean
.
MyAppTest3.java
@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = AppTestConfig.class) public class MyAppTest3 { @Autowired private MyService1 myService1; @Autowired private MyService2 myService2; @Test public void testApp1() { Mockito.when(myService1.getMessage()).thenReturn("Welcome"); String msg = myService1.getMessage(); assertEquals("Welcome", msg); } @Test public void testApp2() { Mockito.when(myService2.getCount()).thenReturn(100); int count = myService2.getCount(); assertEquals(100, count); } } @Configuration class AppTestConfig { @MockBean private MyService1 myService1; @MockBean private MyService2 myService2; }
@Autowired
annotation.
@MockBean with @Qualifier
If an interface has more than one implementation class then to choose the exact class for dependency injection,@Qualifier
annotation is used. Here we will show the demo to use @MockBean
with @Qualifier
annotation.
MyAppTest4.java
@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = AppConfig.class) public class MyAppTest4 { @MockBean @Qualifier("deer") private Animal animal1; @MockBean @Qualifier("fox") private Animal animal2; @Test public void testApp1() { Mockito.when(animal1.getName()).thenReturn("xxx"); assertEquals("xxx", animal1.getName()); } @Test public void testApp2() { Mockito.when(animal2.getName()).thenReturn("yyy"); assertEquals("yyy", animal2.getName()); } }
Find the classes used in our unit test class.
Animal.java
public interface Animal { String getName(); }
@Component("deer") public class Deer implements Animal { @Override public String getName() { return "Deer"; } }
@Component("fox") public class Fox implements Animal { @Override public String getName() { return "Fox"; } }

References
Annotation Type MockBeanAnnotation Type MockBeans