Difference between @Mock, @MockBean and Mockito.mock()
Plain Mockito library
import org.mockito.Mock;
...
@Mock
MyService myservice;
and
import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);
come from the Mockito library and are functionally equivalent.
They allow to mock a class or an interface and to record and verify behaviors on it.
The way using annotation is shorter, so preferable and often preferred.
Note that to enable Mockito annotations during test executions, theMockitoAnnotations.initMocks(this)
static method has to be called.
To avoid side effect between tests, it is advised to do it before each test execution :
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
Another way to enable Mockito annotations is annotating the test class with @RunWith
by specifying the MockitoJUnitRunner
that does this task and also other useful things :
@RunWith(org.mockito.runners.MockitoJUnitRunner.class)
public MyClassTest{...}
Spring Boot library wrapping Mockito library
This is indeed a Spring Boot class:
import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;
The class is included in the spring-boot-test
library.
It allows to add Mockito mocks in a Spring ApplicationContext
.
If a bean, compatible with the declared class exists in the context, it replaces it by the mock.
If it is not the case, it adds the mock in the context as a bean.
Javadoc reference :
Annotation that can be used to add mocks to a Spring
ApplicationContext....
If any existing single bean of the same type defined in the context
will be replaced by the mock, if no existing bean is defined a new one
will be added.
When use classic/plain Mockito and when use @MockBean
from Spring Boot ?
Unit tests are designed to test a component in isolation from other components and unit tests have also a requirement : being as fast as possible in terms of execution time as these tests may be executed each day dozen times on the developer machines.
Consequently, here is a simple guideline :
As you write a test that doesn't need any dependencies from the Spring Boot container, the classic/plain Mockito is the way to follow : it is fast and favors the isolation of the tested component.
If your test needs to rely on the Spring Boot container and you want also to add or mock one of the container beans : @MockBean
from Spring Boot is the way.
Typical usage of Spring Boot @MockBean
As we write a test class annotated with @WebMvcTest
(web test slice).
The Spring Boot documentation summarizes that very well :
Often
@WebMvcTest
will be limited to a single controller and used in
combination with@MockBean
to provide mock implementations for
required collaborators.
Here is an example :
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private FooService fooServiceMock;
@Test
public void testExample() throws Exception {
Foo mockedFoo = new Foo("one", "two");
Mockito.when(fooServiceMock.get(1))
.thenReturn(mockedFoo);
mvc.perform(get("foos/1")
.accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().string("one two"));
}
}
When to use and not use @Mock annotation, @MockBean annotation, @InjectMock annotation & @Autowired annotation in a spring webflux reactive project
@Mock
Used to make Mockito create a mock object.
@InjectMock
When you want Mockito to create an instance of an object and use the mocks annotated with @Mock
as its dependencies.
@AutoWired
Used when you want to autowire a bean from the spring context, works exactly the same as in normal code but can only be used in tests that actually creates an application context, such as tests annotated with @WebMvcTest
or @SpringBootTest
.
@MockBean
Can be used to add mock objects to the Spring application context. The mock will replace any existing bean of the same type in the application context. If no bean of the same type is defined, a new one will be added. Often used together with @SpringBootTest
So normally you either:
- Use
@Mock
and@InjectMocks
for running tests without a spring
context, this is preferred as it's much faster. - Use
@SpringBootTest
or@SpringMvcTest
to start a spring context together with@MockBean
to create mock objects and@Autowired
to get an instance of class you want to test, the mockeans will be used for its autowired dependencies. You use this when writing integration tests for code that interact with a database or want to test your REST API.
What is difference here - @Autowired and @MockBean
A @SpringBootTest is a test that actually starts up a Spring container along with the beans of the application.
@Autowired fields in tests behave like they do in normal Spring-Beans; they get injected with the actual beans configured in the application (xml, @Bean in a @Configuration, or @Component/@Service).
@MockBean creates a mock that they behave like normal mocks that you can control with when/then
etc and check with verify
and suchlike. The thing that is special about them is that they get injected into other beans in the context (for instance when you call Mockito.initAnnotations(this)
).
What is difference between @SpyBean and @MockBean in Mockito?
A mock (no matter if we talk about ordinary objects or beans) is simply an "empty shell".
That mock object doesn't have any relation to the underlying production code. It is an object that looks like being an object of class X. But none of the methods or fields that X has do "really" exist on that mocked thing.
Whereas a spy wraps around an existing object of your class under test. Meaning: when you create a spy, you can decide if method calls going to the spy should be "intercepted" (then you are using the spy as if it would be a mock); or be "passed through" to the actual object the spy wraps around.
See here for further reading.
@MockBean and @Autowired of the same service in one test class
The best solution is to change @MockBean
to @SpyBean. And in the method you will be able to do like this:
kotlin
@SpyBean
lateinit var serviceMock: Service
@Test
fun smallTest()
`when`(serviceMock.doSomething())
.thenReturn(false)
// your test logic
}
What is the difference between mockito-core and mockito-all
mockito-core
only contains mockito classes, while mockito-all
contain mockito classes as well as some dependencies, one of them being hamcrest.
In fact mockito-all
is discontinued according to the mockito website
“mockito-all” distribution has been discontinued in Mockito 2.*.
The two packages were/are equivalent but if you depend on mockito-core
you'll need to add a specific dependency on the packages transitively included in mockito-all
if you require them in your project.
I've personally experienced some issues when depending on a newer version some hamcrest
matchers while at the same time having a dependency on mockito-all
.
Related Topics
How to Define a List Bean in Spring
How to Replace the Awt Eventqueue with Own Implementation
Why Invoke Thread.Currentthread.Interrupt() in a Catch Interruptexception Block
How Is an Instance Initializer Different from a Constructor
Why Doesn't Java Map Extend Collection
Java.Awt.Eventqueue.Invokelater Explained
List of Useful Environment Settings in Java
Parsing a Date's Ordinal Indicator ( St, Nd, Rd, Th ) in a Date-Time String
Ignore Fields from Java Object Dynamically While Sending as JSON from Spring MVC
What Causes "Unable to Access Jarfile" Error
Java Error: Only a Type Can Be Imported. Xyz Resolves to a Package
Jvm Takes a Long Time to Resolve Ip-Address for Localhost
Is an Array a Primitive Type or an Object (Or Something Else Entirely)
Java Annotations Values Provided in Dynamic Manner
Spring Boot Adding Http Request Interceptors
How to Annotate MySQL Autoincrement Field with JPA Annotations