@Mock
is used to create a mock object of a class or interface. Mock objects are used in testing to simulate the behavior of a real object or component that the test depends on. When a method of the mock object is called during the test, it will return a pre-configured response, allowing the test to simulate the behavior of the real object without having to actually interact with it.
@MockBean
, on the other hand, is used to create a mock object of a Spring bean. Spring beans are Java objects managed by the Spring container and used throughout an application. The @MockBean
annotation can be used to replace a real bean with a mock object in the Spring application context during a test. This allows the test to control the behavior of the bean and simulate different scenarios, without affecting the behavior of the real bean.
Both @Mock
and @MockBean
are useful for testing Spring applications and can help isolate the code being tested by removing dependencies on other components. This makes tests more reliable and easier to maintain, as changes to other components in the application will not affect the behavior of the test.
One key difference between @Mock
and @MockBean
is that @MockBean
creates a mock object and adds it to the Spring application context, while @Mock
creates a standalone mock object. This means that @MockBean
can be used to replace a real bean with a mock object in the Spring context, while @Mock
is typically used to create standalone mock objects for non-Spring classes.
@InjectMocks
is used to inject those mock objects into the object being tested. It is typically used to inject mock objects into a class under test, in order to replace any real dependencies with mock objects. @InjectMocks
can be used in combination with @Mock
and @MockBean
to create a test object with all the necessary dependencies injected.
Example:
@Service
public class MyService {
@Autowired
private MyRepository repository;
public void doSomething() {
// Do something using the repository
repository.save(new MyEntity());
}
}
@Repository
public class MyRepository {
public void save(MyEntity entity) {
// Save the entity to the database
}
}
In this case, we have a MyService
class that depends on a MyRepository
Spring bean.
Then let's write a test using @Mock and @InjectMocks:
public class MyServiceTest {
@Mock
private MyRepository repository;
@InjectMocks
private MyService service;
@Test
public void testDoSomething() {
// Configure the mock object
doNothing().when(repository).save(any(MyEntity.class));
// Call the method being tested
service.doSomething();
// Verify that the repository.save method was called
verify(repository, times(1)).save(any(MyEntity.class));
}
}
we create a mock object of MyRepository
using the @Mock
annotation.
And we also use @InjectMocks
annotation, it will do two important thing:
1. creates an instance of the class MyService
2. injects the mocks that are created with the @Mock
(or @Spy
) annotations into this instance.
We can also write a test using just @MockBean:
@SpringBootTest
public class MyServiceTest {
@MockBean
private MyRepository repository;
@Autowired
private MyService service;
@Test
public void testDoSomething() {
// Configure the mock object
doNothing().when(repository).save(any(MyEntity.class));
// Call the method being tested
service.doSomething();
// Verify that the repository.save method was called
verify(repository, times(1)).save(any(MyEntity.class));
}
}
In this case, we use @MockBean
to create a mock MyRepository
bean, which is added to the Spring application context.
When using @MockBean
, Spring replaces the actual bean in the application context with the mock bean during the test. The MyService
bean is then injected with this mock bean instead of the real MyRepository
bean.
The above example are the two ways to write the same test.