I want to InjectMocks into my interface and not my service class , so far its not possible with Mockito (I am using Mockito 2.8.9). I have used SpringBoot and using #MockBean I am able to test interfaces of services but with #Mock of SpringMvc I can only test a concrete class, why and what can I do to test services?
Any suggestion on how to get this to interface level.
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(classes = EmployeeServiceImpl.class)
public class EmployeeServiceTest {
#org.mockito.Mock
private EmployeeDao employeeDao;
#InjectMocks
private EmployeeServiceImpl employeeService ;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
#Test
public void SaveEmployee() throws Exception {
Employee employee = new Employee();
employee.setEmployeeName("valentine");
employee.setSalary(400);
employee.setDepartmentId(1);
employee.setEmployeeId(1);
Employee employee1 ;
when(employeeDao.addEmployee(employee)).thenReturn(employee);
employee1 = employeeService.saveEmployee(employee);
org.junit.Assert.assertNotNull(employee);
assertEquals(employee1.getSalary(), employee.getSalary());
Mockito.verify(employeeDao).addEmployee(employee);
}
So i solved this by first creating Bean in Config class that returns interface of Dao
#Profile("test")
#Configuration
public class Config {
#Bean
#Primary
public EmployeeDao employeeDao(){
return Mockito.mock(EmployeeDao.class);
}
}
Then i used the profile in my test and set configContxt TO my Config Class
#ActiveProfiles("test")
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes ={ EmployeeServiceImpl.class, Config.class})
public class EmployeeServiceTest1 {
#Autowired
private EmployeeDao employeeDao;
#Autowired
private EmployeeService employeeService;
Related
I am creating test cases, in one of my service class method I am using mapStruct to map entity into dto class.
This is my mapper class
#Mapper(componentModel = "spring")
public interface UserMapper {
List<UserDto> toUserDto(List<UserEntity> users);
}
below is how I am injecting in my service class
#Service
#RequiredArgsConstructor
public class UserServiceImpl implements UserService{
private final UserMapper userMapper;
This is how I am using it
List<UserDto> userDto = userMapper.toUserDto(lst);
this is how I am doing it in my Test class
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(classes = Application.class)
public class ApplicationTest {
#Mock
private UserRepository userRepo;
#Mock
private UserMapper userMapper;
#InjectMocks
private UserServiceImpl userServiceImpl;
#Test
public void contextLoads() {
then(controller).isNotNull();
then(userServiceImpl).isNotNull();
}
#Test
public void getAllUser() {
List<UserEntity> lst = new ArrayList<UserEntity>();
UserEntity userOne = new UserEntity();
userOne.setEmpFullname("Test Test1");
userOne.setUserId("marina");
userOne.setFlag("Y");
UserEntity usertwo = new UserEntity();
usertwo.setEmpFullname("Test Test2");
usertwo.setUserId("test");
usertwo.setFlag("Y");
lst.add(userOne);
lst.add(usertwo);
when(userRepo.findByStatus("W")).thenReturn(lst);
try {
List<UserDto> pendingUsersList = userServiceImpl.getPendingUser();
assertEquals(2, pendingUsersList.size());
} catch (GeneralException e) {
e.printStackTrace();
}
}
}
when I am running my test cases I am able to see these 2 records in entity class but when this line executes
List<UserDto> userDto = userMapper.toUserDto(lst); it gives me blank array.
Note - In my entity Class I have many fields but from test class I am passing only 3 parameters.
You have annotated your UserMapper with a #Mock annotation, without writing the mockito configuration for this mock. Then the blank array is expected.
Remove the #Mock annotation, or specify what should be returned by the mock.
For example :
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(classes = Application.class)
public class ApplicationTest {
#Mock
private UserRepository userRepo;
#Spy
private UserMapper userMapper = Mappers.getMapper(UserMapper.class);
#InjectMocks
private UserServiceImpl userServiceImpl;
So I have this class (used lombok):
#RequiredArgsConstructor
#Service
public class ServiceImpl {
private final BookService bookService;
#Autowired
private TableService tableService;
public void method() {
if (!bookService.isEmpty()) return;
Object table = tableService.getObject();
}
}
My test class:
#ExtendWith(MockitoExtension.class)
#RunWith(JUnitPlatform.class)
public class ServiceImplTest {
#Mock BookService bookService;
#Mock TableService tableService;
#InjectMocks ServiceImpl serviceImpl;
#Test
public void testMethod() {
when(bookService.isEmpty()).thenReturn(true);
when(tableService.isEmpty()).thenReturn(new Object());
serviceImpl.method();
}
}
If I run it, the bookService is null. It is not injected in the class. When the code is at the if (!bookService.isEmpty()) return; the bookService is null.
if I change my testMethod to this:
#Test
public void testMethod() {
MockitoAnnotations.initMocks(this);
when(bookService.isEmpty()).thenReturn(true);
when(tableService.isEmpty()).thenReturn(new Object());
serviceImpl.method();
}
So I added MockitoAnnotations.initMocks(this); then the code Object table = tableService.getObject(); in my class returns null. So the tableService is not null, but the getObject() return null;
Any idea how to fix it? I am not let to change the class code.
Thanks in advance.
I have problems with configuring tests for SpringJUnit4ClassRunner.class).
My problem is because my mapper from map struct returns null when reached.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
class UserServiceTestSuite {
#Spy
private UserDto userDto;
#Spy
private UserMapper userMapper;
#Mock
private UserRepository userRepository;
#InjectMocks
private UserService userService;
private User createUser() {
return User.builder()
.firstName("Steve")
.lastName("Jobs")
.login("SteveJobs")
.password("password")
.role(UserRole.ROLE_ADMIN)
.build();
}
#Test
public void testCreateUser() {
//Given
User user = createUser();
Mockito.when(userRepository.save(user)).thenReturn(user);
//When
UserDto userDto = userService.createUser(userMapper.mapToUserDto(user));
Long id = userDto.getId();
//Then
Assert.assertEquals("Steve", userDto.getFirstName());
Assert.assertEquals("Jobs", userDto.getLastName());
Assert.assertEquals("SteveJobs", userDto.getLogin());
Assert.assertEquals("ROLE_ADMIN", userDto.getRole());
}
In my opinion you have two options:
Inject the mapper via #SpringBootTest(classes = {UserMapperImpl.class}) and
#Autowired
private UserMapper userMapper;
Simply initialize the Mapper private UserMapper userMapper = new UserMapperImpl() (and remove #Spy)
When using the second approach you can even remove the #SpringBootTest because in the given snippet you do not need a Spring context (created by the annotation).
#RunWith(MockitoJUnitRunner.class) can be used to automatically inject objects annotated with #Mock into your UserService. Writing unit tests without creating a spring context helps to keep test suite execution time low.
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO userMapper.mapToUserDto(Object value);
}
Using this mapper interface you can instantiate from the mock and use the methods.
For example:
#Mock
private UserMapper userMapper;
Init the mocks:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
and you use the call INSTANCE
UserDto userDto = userService.createUser(userMapper.INSTANCE.mapToUserDto(user));
I have a spring boot test as below
#SpringBootTest(class=AppConfig.class)
Public class AppTest{
#Autowired
private Product product
#Test
Public void test(){
.....
.....
}
}
My AppConfig.class is as below
Public clas AppConfig{
#Mock
EMailService emailService;
public AppConfig(){
MockitoAnnotations.initMocks(this)
}
#Bean
Public Product getProduct(){
return new Product();
}
}
Class Product{
#Autowired
private EMailService emailService
.....
......
}
Even after i defined #Mock EMailService emailService, whem i run the test, I get error EMailService bean not defined.
In your AppTest class
#SpringBootTest(class=AppConfig.class)
public class AppTest{
#Mock
private EMailService emailService;
#InjectMocks
private Product product;
#Test
public void test(){
.....
.....
}
}
Also, I think you do not need the definitions in the AppConfig class anymore
Is there any way to inject non-mocked objects with #InjectMocks?
My Setup has a UserSignupService with dependencies to a MailService and a UserRepository (a Spring Data Repository). I've a unit test creating a spy of the MailService and I annotated the UserSignupService with #InjectMocks. Sadly this won't inject the UserRepository (non-mocked) into the service class.
Combining #InjectMocks with #Autowired won't inject the mocked MailService, but the bean from the application context.
MockitoAnnotations.initMocks() is run in AbstractServiceTest.setUp(). This class also holds the configuration of the the unit test (SpringJunit4TestRunner, etc.)
public class UserSignupServiceTest extends AbstractServiceTest {
#Autowired #Spy
private MailService<UserActivationMail> mailService;
#InjectMocks
private UserSignupServiceImpl service;
#Before
public void setUp() throws Exception {
super.setUp();
}
}
#Service
public class UserSignupServiceImpl implements UserSignupService {
private final UserRepository repository;
private final MailService<UserActivationMail> mailService;
#Autowired
public UserSignupServiceImpl(UserRepository repository,
MailService<UserActivationMail> mailService) {
this.repository = repository;
this.mailService = mailService;
}
//methods...
}
You need to initialize your Mockito MockitoAnnotations.initMocks(this);
Here is sample Spring JUnit test class I have
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:config/spring-context.xml" })
public class SpringKPTest {
#Autowired
SomeClassA SomeClassA;
#Mock
SomeClassB SomeClassB;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
}