I use Project Lombok for my Java projects.
My Controller looks like this:
#RestController
#AllArgsConstructor
public class UserController {
private RegisterService registerService;
private UserService userService;
private UserValidator userValidator;
private LoginService loginService;
/*
* rest of the controller
*/
}
so the controller must look like this:
#WebMvcTest(UserController.class)
public class UserControllerTest {
#MockBean
private UserRepository userRepository;
#MockBean
private RegisterService registerService;
#MockBean
private UserService userService;
#MockBean
private LoginService loginService;
#MockBean
private UserValidator UserValidator;
/*
* rest of the contoller test
*/
}
Just to make programming less code-monkey, is there anything like #AllMockArgConstructor?
Or any way, I don't always have to add all services?
If this is a stupid question, please explain me why.
Thanks in advance!
Unfortunately it cannot be done,
#MockBeans annotation target is applied only to fields and types, and not for methods, you can read more about it here.
If #MockBeans was able to support also methods then it was can be done that way:
#Getter(onMethod_={#MockBean} )
#WebMvcTest(UserController.class)
public class UserControllerTest {
...
}
Related
I wonder whether it's possible to replace all the Autowired fields with final ones and #RequiredArgsConstructor below the class declaration?
For instance, replace the following code
public class Controller {
#Autowired
private Reposiroty repository;
#Autowired
private Service service;
...
}
with something like that:
#RequiredArgsConstructor
public class Controller {
private final Reposiroty repository;
private final Service service;
...
}
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 was going through the Spring tutorial and I found below code snippet:
public class EmployeeRestController {
private Logger logger = LoggerFactory.getLogger(EmployeeRestController.class);
#Autowired
private EmployeeService employeeService;
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
My Question is that Why this method is used even though the is no call of this method.:
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
Thanks
I believe this setter method has no significance if you use spring dependency injection to set the dependency on a class property. That's what is happening to EmployeeRestController by using #Autowired annotation to employee service property private EmployeeService employeeService; You can also use setter level dependency injection this way
#Autowired
public void setEmployeeService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
It's a good and suggested practice to use #Autowired on setter instead of private properties.
if you have used #Autowired then no requirement of setmethod so refer below code:
#Controller
public class EmployeeRestController {
private Logger logger = LoggerFactory.getLogger(EmployeeRestController.class);
#Autowired
private EmployeeService employeeService;
}
#Service
public class EmployeeService{
}
I have a bit of mess with Mockito and fields annotated with #Spy .
I want to test this class:
#Service
public class CategoryServiceImpl implements CategoryService {
#Autowire
private CategoryRepository categoryRepository;
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#Autowired
public void createMapper(final Mapper mapper) {
boundMapper = mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class);
}
// Rest of methods...
}
So, I have created a testing class as shown below:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
#Spy
private BoundMapperFacade<CategoryDTO, Category> boundMapper;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
When Mockito instances categoryServiceImpl injects categoryRepository as a mock class but it does not know how to create boundMapper. This class depends on mapper, so I have rewritten my code:
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = spy(mapper.getMapperFactory().getMapperFacade(
CategoryDTO.class, Category.class));
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
// Rest of methods...
}
But now the problem is the creation of boundMapper is executed before Mockito injects mapper, so I get a NullPointerException.
So, is there any way to create an spy class who depends on another one and finally inject this last one in a field tagged as #InjectMocks?
If you have a spy that depends on a mock or a spy, the only way I've seen to do it is inside the #Before decorated function.
#RunWith(MockitoJUnitRunner.class)
public class CategoryServiceImplTest {
#Mock
private CategoryRepository categoryRepository;
#Spy
private Mapper mapper;
private BoundMapperFacade<CategoryDTO, Category> boundMapper = ;
#InjectMocks
private CategoryServiceImpl categoryServiceImpl;
#Before
public void setup() {
boundMapper = spy(mapper
.getMapperFactory()
.getMapperFacade(CategoryDTO.class, Category.class)
);
}
// Rest of methods...
}
I'm not sure how this works with #InjectMocks, so that might be something to look into. There might be a non-decorator version of it that you can run after boundMapper is initialized if CategoryServiceImpl is dependent on it.
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);
}
}