How to return Page content in Spring Boot Unit test service layer? How to mock this data with some values and later on test it?
Service that needs to be tested:
#Service
#RequiredArgsConstructor
#Transactional(readOnly = true)
public class CampaignReadServiceImpl02 {
private final CampaignRepository campaignRepository;
public Page<Campaign> getAll(int page, int size) {
Pageable pageable = PageRequest.of(page, size);
Page<Campaign> pages = campaignRepository.findAll(pageable);
return pages;
}
}
The class that mocks data in Unit test
#Slf4j
#ExtendWith(MockitoExtension.class)
public class CampaignReadServiceTest {
#Mock
private CampaignRepository campaignRepository;
private CampaignReadServiceImpl02 campaignReadServiceImpl02;
#BeforeEach
public void beforeEach() {
campaignReadServiceImpl02 = new CampaignReadServiceImpl02(campaignRepository);
}
#Test
public void testGetAll02() {
log.info("Testing get all campaigns method");
//this need to have content data inside of page.getContent(), need to be added
Page<Campaign> page = Mockito.mock(Page.class);
Mockito.when(campaignRepository.findAll(Mockito.any(Pageable.class))).thenReturn(page);
Page<Campaign> result = campaignReadServiceImpl02.getAll(2, 2);
Assertions.assertNotNull(result);
Mockito.verify(campaignRepository, Mockito.times(1)).findAll(Mockito.any(Pageable.class));
Mockito.verifyNoMoreInteractions(campaignRepository);
}
}
How to mock Page<Campaign> page = Mockito.mock(Page.class); to get result.getContent(); when Service repository is injected in Service..
I can't test result.getContent() because I don't have data from repository, maube because I need to change mock Page<Campaign> page with Page.class to something else?
How to properly mock Page<Campaign> page = Mockito.mock(Page.class); that will return some data later on in service: result.getContent().name(), etc..
easiest way would be to create an object instead of mocking the class.
Page<TournamentEntity> tournamentEntitiesPage = new PageImpl<>(List.of(obj1, obj2), pageable, 0);
Related
Im testing my service with Junit but the result is not the expected.
When i save my entity, the return date is not setted in service.
Test:
#Test
#DisplayName("Should set determined time for return date")
public void shouldSetReturnDate() {
ClientDTORequest dto = createNewDTOClient();
Client client = createNewClient();
Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client);
Client saved = clientService.save(dto);
Assertions.assertEquals(dateTimeNow.plusMinutes(30), saved.getReturnDate());
}
My createNewClient():
private Client createNewClient() {
//the null param is the return date
return new Client(1L, "name", null);
}
My service:
public Client save(ClientDTORequest dto) {
Client client = mapper.map(dto, Client.class);
client.setReturnDate(dateTimeNow.plusMinutes(30));
Client savedClient = clientRepository.save(client);
return savedClient;
}
And when the test result:
org.opentest4j.AssertionFailedError:
Expected :2022-04-04T01:17:25.715895900
Actual :null
The result is not passed by the service to mock, this is my shot, but i dont know why.
Thanks!
The problem is you're coupled to "now", so the service always will have the time at the moment it runs.
One of the best ways of work with time is by modeling the concept Clock or TimeProvider and injecting it to the Service. Then you can mock it to assert the time in the test.
class Clock {
LocalDateTime now() {
return LocalDateTime.now().plusMinutes(30); // <-- as you needs
}
}
class Service {
private Clock clock;
Service(Clock clock) {
this.clock = clock;
}
void save(MyEntity entity) {
entity.setCreatedDateTime(clock.now());
//repositoty.save(entity);
}
}
#Getter
class MyEntity {
private LocalDateTime createdDateTime;
public void setCreatedDateTime(LocalDateTime createdDateTime) {
//assing it to a field
this.createdDateTime = createdDateTime;
}
}
class ServiceTest {
#Mock
private Clock clock;
private Service service;
#Test
void testSave() {
LocalDateTime fixedDateTimeNow = LocalDateTime.of(2022, 4, 3, 18, 0, 0);
Mockito.when(clock.now()).thenReturn(fixedDateTimeNow);
MyEntity entity = new MyEntity();
service.save(entity);
Assertions.assertEquals(fixedDateTimeNow, entity.getCreatedDateTime());
}
}
Note: Be careful about holding state in your service, so it's not thread safe. So, you'll end up with concurrency problems when multiple calls to service occurs "at the same time".
If you injected your clientRepository with #Autowired then it won't mock. Try #SpyBean
(#Autowired ClientRepository clientRepository wouldn't mock; #SpyBean ClientRepository clientRepository should mock)
After some hours of testing i found the problem:
My service was changing data, but was overridden by my mock:
Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client); <-- mock overridden the changed data from service
Client saved = clientService.save(dto);
So i found ArgumentCaptor, where i can get the object from method call:
Declaring the Captor:
#Captor
ArgumentCaptor<Client> clientCaptor;
Using at test method:
Mockito.when(clientRepository.save(clientCaptor.capture())).thenReturn(client); //<-- capturing the result
clientService.save(dto);
Client saved = clientCaptor.getValue() //getting object
Assertions.assertEquals(dto.getReturnDate().plusMinutes(30), saved.getReturnDate()); //assertion
I'm trying to test my Spring Hateoas application, more specifically the controllers, using Springs #WebMvcTest. But I'm having problems injecting my custom RepresentationModelAssembler into the test.
First a bit of my setup:
I'm using a custom RepresentationModelAssembler to turn my DB-Models into DTOs, which have all necessary links added.
The RepresentationModelAssembler:
#Component
public class BusinessUnitAssembler implements RepresentationModelAssembler<BusinessUnit, BusinessUnitDto> {
private final Class<BusinessUnitController> controllerClass = BusinessUnitController.class;
private final BusinessUnitMapper businessUnitMapper;
public BusinessUnitAssembler(BusinessUnitMapper businessUnitMapper) {
this.businessUnitMapper = businessUnitMapper;
}
#Override
public BusinessUnitDto toModel(BusinessUnit entity) {
return businessUnitMapper.businessUnitToDto(entity)
.add(linkTo(methodOn(controllerClass).findById(entity.getId())).withSelfRel());
}
}
The BusinessUnitMapper used here is a Mapstruct mapper, which is injected by spring. In my Service I use the BusinessUnitAssembler to turn my DB-Models into DTOs, example Service method:
public Page<BusinessUnitDto> findAll(Pageable pageable) {
Page<BusinessUnit> pagedResult = businessUnitRepository.findAll(pageable);
if (pagedResult.hasContent()) {
return pagedResult.map(businessUnitAssembler::toModel);
} else {
return Page.empty();
}
}
This is how I'm doing the testing currently:
#WebMvcTest(controllers = BusinessUnitController.class)
public class BusinessUnitControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private BusinessUnitService businessUnitService;
private BusinessUnitMapper mapper = Mappers.getMapper(BusinessUnitMapper.class);
private BusinessUnitAssembler assembler = new BusinessUnitAssembler(mapper);
#Test
public void getAllShouldReturnAllBusinessUnits() throws Exception {
List<BusinessUnitDto> businessUnits = Stream.of(
new BusinessUnit(1L, "Personal"),
new BusinessUnit(2L, "IT")
).map(businessUnit -> assembler.toModel(businessUnit)).collect(Collectors.toList());
when(businessUnitService.findAll(Pageable.ofSize(10))).thenReturn(new PageImpl<>(businessUnits));
mockMvc.perform(get("/businessUnits").accept(MediaTypes.HAL_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.*", hasSize(3)))
// ... do more jsonPath checking
}
}
But I'd like to have Spring inject the BusinessUnitAssembler, instead of constructing it myself. I've tried #Importing BusinessUnitAssembler as well as the BusinessUnitMapper and I've also tried it by using a custom #Configuration but I just couldn't get it to work.
So my Question is: How can I let Spring inject my BusinessUnitAssembler into the test for me instead of assembling it myself?
Additional Question: Is it valid to combine the Mapping from Database Entity to DTO in the RepresentationModelAssembler or should those two steps be kept seperate from each other?
Consider:
#GetMapping(path = {"/attachment/answer/{answerId}"})
public APIResponse<List<AttachmentVM>> getAttachmentListForAnswer(#PathVariable("answerId") UUID answerId) {
List<AttachmentBO> attachmentBOList = this.attachmentService.getAttachmentListForAnswer(answerId);
List<AttachmentVM> noteVMList = super.mapList(attachmentBOList, AttachmentVM.class);
return APIResponse.ok(noteVMList);
}
How can we write a JUnit testcase for this Controller using Mockito, using Mockito.when, and then return?
If you want to test your API, I would suggest Wiremock instead of Mockito.
#Test
public void shouldGetEndpoint() {
String path = "/endpoint";
wiremock.stubFor(get(urlEqualTo(path))
.willReturn(aResponse()
.withStatus(200))
);
}
If you want to write a unit test for your class by mocking attachmentService, you will need to do something like:
List<AttachmentBO> providedList = new ArrayList<>();
MyService attachmentService = Mockito.mock(MyService.class);
when(attachmentService.getAttachmentListForAnswer(any())).thenReturn(providedList);
Check out this tutorial
I'm assuming you're using Spring Boot.
#Autowired private MockMvc mockMvc;
#MockBean private AttachmentService attachmentService;
#Test public void test() {
List<AttachmentBO> attachmentBOList = new ArrayList<>();
String answerId = "myId";
// mocking your service here by directly returning the list
// instead of executing the code of the service class
Mockito.when(attachmentService.getAttachmentListForAnswer(answerId))
.thenReturn(attachmentBOList);
// calling the controller
String url = "/attachment/answer/" + answerId;
this.mockMvc.perform(MockMvcRequestBuilders.get(url))
.andExpect(MockMvcResultMatchers.status.isOk());
I working on writing tests for a crud application. I need to test the service and repository for Delete and Update statements. How would I go about mocking the repository for delete and update since they won't be returning data?
For example:
#Override
public void makeUserActive(long userId) {
try {
Optional<UserEntity> userEntityList = usersJpaRepository.findById(userId);
UserEntity userEntity = userEntityList.get();
userEntity.setIsActive(1);
usersJpaRepository.save(userEntity);
} catch (Exception e) {
logger.error("Cant make active user", e);
}
}
How do i test the service that mocks this repository and also the repository itself since it wont be returning a value
The question is what is the thing you want to be tested?
If you would like to test your repository you can achieve this by using Springs #DataJpaTest. see Integration Testing With #DataJpaTest
If you would like to test the logic inside your makeUserActive-Method you must make sure to mock your repository.
Assuming the service which contains your makeUserActive-Method looks something like this:
public class UserService{
private final UsersJpaRepository usersJpaRepository;
public UserService(UsersJpaRepository usersJpaRepository) {
this.usersJpaRepository = usersJpaRepository;
}
public void makeUserActive(long userId){
// your code from your question
}
}
You could write your Unit Test like this:
#Test
void makeUserActiveTest(){
UsersJpaRepository repository = new InMemoryUsersJpaRepository();
UserEntity user = new UserEntity();
user = repository.save(user);
UserService service = new UserService(repository);
service.makeUserActive(user.getId());
Optional<UserEntity> activatedUser = repository.findById(user.getId());
assertTrue(activatedUser.isPresent());
assertEquals(1, activatedUser.get().isActive());
}
The InMemoryUsersJpaRepository is a self written Mock which will store all data in an internal Map. The code could look something like this:
public class InMemoryUsersJpaRepository extends UsersJpaRepository {
private Map<Long, UserEntity> users = new HashMap<>();
private Long idCounter = 1L;
#Override
public UserEntity save(UserEntity user) {
if(user.getId() == null){
user.setId(idCounter);
idCounter++;
}
users.put(user.getId(), user);
return user;
}
#Override
public Optional<UserEntity> findById(long userId) {
return Optional.of(users.get(userId));
}
}
This way you will test the logic of your makeUserActive-Method which is currently to simply set the isActivated Flag on you UserEntity.
Also I would like to warn you about the answer of Mensur Qulami.
The Code in his answer will lead to a passing test but I'am pretty sure it does not test the thing you want to be tested.
You should always test the expected and observable behaviour of your method.
In your case this would be the isActivated Flag that should be 1.
The fact that your makeUserActive-Method calls the findById and save Method of the UsersJpaRepository is a mere implementation detail and the testing of those generally lead to brittle tests.
For the methods returning void, you can simply verify that they have been called. Here's an example, that mocks both an object returning method and void returning method.
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Mock
private Repository repository;
#InjectMocks
private Service service; // assume that this is your class
#Test
void testMakeUserActive() {
// given:
final UserEntity userEntity = new UserEntity();
// mocks:
when(repository.findById(1)).thenReturn(Optional.of(userEntity));
// when:
service.makeUserActive(1);
// then:
verify(repository).findById(1);
verify(repository).save(userEntity);
}
}
I'm using the Dropwizard framework and I'm trying to mock certain objects inside a web resource (the web resource tries to communicate with something external and I want to mock that).
Currently, I'm running the Dropwizard application in my tests through:
#PowerMockIgnore({"org.apache.http.conn.ssl.*", "javax.net.ssl.*", "javax.crypto.*", "javax.management.*", "javax.net.*"})
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ExternalCommunicator.class})
public class MockTest {
#ClassRule
public static final DropwizardAppRule<ApplicationWebserviceConfiguration> RULE = new DropwizardAppRule<>(ApplicationWebserviceApplication.class, ResourceHelpers.resourceFilePath("config.yml"));
#Before
public void doStuff() {
final ExternalCommunicator externalCommunicator = mock(ExternalCommunicator.class);
whenNew(ExternalCommunicator.class).withAnyArguments().thenReturn(externalCommunicator);
}
My resource looks something like:
#GET
#Path("/{id}")
#Timed
#UnitOfWork
#ApiOperation(value = "Talk to things", notes = "Talk to things.", response = String.class)
public String talk(#ApiParam(value = "id", required = true) #PathParam("id") Long id) {
ExternalCommunicator communicator = new ExternalCommunicator(id);
String result = communicator.get();
someDAO.create(result);
return result;
}
I'm using powermock and mockito but can't seem to correctly mock ExternalCommunicator
I've also tried
#Rule
public PowerMockRule rule = new PowerMockRule();
instead of #RunWith(PowerMockRunner.class) annotation but that doesn't seem to work either
Additionally, I do not want to mock the DAO.