Service in Spring not setting values with Junit - java

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

Related

How to mock Page with content data in Unit Test?

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);

Unit Test: Cannot get value from Service in Java

I am trying to test the following method that gets data from Price service.
CountryServiceImpl:
public PriceDTO findBCountryUuid(UUID countryUuid) {
// code omitted
// !!! currency value is null
Currency currency = currencyService.getCurrencyByCountry(countryUuid);
return new PriceDTO(currency);
}
Here is the PriceService.
PriceServiceImpl:
#Override
public Currency getCurrencyByCountry(UUID countryUuid) {
return countryRepository.findByUuid(countryUuid)
.orElseThrow(() -> new EntityNotFoundException("Country"))
.getCurrency();
}
I use the following approach to test:
#Mock
private CountryRepository countryRepository;
#Mock
private CurrencyServiceImpl currencyService;
#InjectMocks
private CountryServiceImpl priceService;
#Test
public void test_findBCountryUuid() {
// code omitted
final Country country = new Country();
country.setName("Country");
country.setCurrency(currency);
when(countryRepository.findByUuid(countryUuid))
.thenReturn(Optional.of(country));
PriceDTO result = priceService.findBCountryUuid(countryUuid);
//... assertions
}
The problem is that; In the findBCountryUuid method, the currency value is null, and for this reason I get null price value in the result parameter of my tets method.
The problem is completely related to using wrong mocking or annotation related to the PriceService. I think I should mock the repo that PriceService uses instead of mocking PriceService. What is wrong with this implementation?
You need to mock the behaviour for the method PriceServiceImpl.getCurrencyByCountry
PriceServiceImpl priceServiceMock = Mockito.mock(PriceServiceImpl.class);
Mockito.when(priceServiceMock.getCurrencyByCountry(any(UUID.class))).thenReturn(new Currency()); // Return either a newly instantiated object or a mockek one based on your need

Test JPA repository for void functions and updates and deletes

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);
}
}

How to mock clock.millis() in Java

I have a code where I calculate the difference between current clock time and time saved in my db
If difference between the two is greater than certain value then I return result accordingly.
For this case I am trying to write test but is facing problem to mock Clock.millis(). I have referred some answers but none worked for me can someone help me with that.
For my test I want to mock this clock.millis() function with a fixed value so that each time I run test it takes that value only.
A Clock is meant for providing access to the current instant, date and time using a time-zone. You don't really need to mock it. As your class needs to obtain the current instant, so it should receive an instance of the Clock in the constructor:
public class FooService {
private final Clock clock;
public FooService(Clock clock) {
this.clock = clock;
}
public boolean isLocked() {
long differenceInSecond = (clock.millis() - this.getLockedAt()) / 1000;
return differenceInSecond < 7200;
}
private long getLockedAt() {
...
}
}
Then, in your test, you can use a fixed() clock, which will always return the same instant:
#Test
public void isLocked_shouldReturnTrue_whenDifferenceInSecondIsSmallerThan7200() {
// Create a fixed clock, which will always return the same instant
Instant instant = Instant.parse("2020-01-01T00:00:00.00Z");
Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
// Create a service instance with the fixed clock
FooService fooService = new FooService(clock);
// Invoke the service method and then assert the result
boolean locked = fooService.isLocked();
assertThat(locked).isTrue();
}
In a Spring Boot application, you could expose a Clock as a #Bean:
#Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
And then Spring will take care of injecting it into your service:
#Service
public class FooService {
private final Clock clock;
public FooService(Clock clock) {
this.clock = clock;
}
...
}
You need to wrap Clockinto your own class, exposing Clock.millis() as a delegate. In your test you can then mock your wrapper and return whatever you like.

How to test business logic in method?

I have such method in my service layer:
public Long calculateItemsCostInShoppingCart(Long shoppingCartId) {
List<Item> items = shoppingCartRepository.findAllItems(shoppingCartId);
Long cost = 0L;
for (Item item : items) {
cost += item.getPrice();
}
return cost;
}
And I need to test calculation of summary cost of all items in list. I was thought about mockito, but it didn't work out cause mockito just create stubs, I need real entrance data and result based on them. How can do it?
// create mock
ShoppingRepository mock = mock(ShoppingRepository.class);
// define return value for method findAllItems()
when(mock.findAllItems()).thenReturn(listOf(...));
Here is an example how you can test it with Mockito:
public class SomeCalculatorTest {
#Mock
private ShoppingCartRepository shoppingCartRepository;
#InjectMocks
private SomeCalculator someCalculator = new SomeCalculator();
#Before
public void setUp() {
initMocks(this);
}
#Test
public void testEmptyItemsList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(new ArrayList<>());
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(0L));
}
#Test
public void testOneItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(25L));
}
#Test
public void testTwoItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L), new ItemImpl(12L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(37L));
}
}
Assuming that you are developing a Java web application which runs on a application server another option might be to use Arquillian (http://arquillian.org/). In a nutshell, Arquillian is a framework which allows you to test you logic in environment it will run. But it might be some work to integrate Arquillian into your project. We are using Arquillian in several projects and it works well so far. Even the Persistence module which is an Alpha version works well.
And I need to test calculation of summary cost of all items in list.
In this case, you have to isolate the shoppingCartRepository dependency that doesn't perform any calculation.
I need real entrance data and result based on them. How can do it?
It describes an integration test. In this case, don't use Mockito.
To unit test :
You have to mock the dependency and you also need a way to set it in the instance of the class under test.
A constructor is often a fine way (let calling the class under test MyService):
public MyService(ShoppingCartRepository shoppingCartRepository){
this.shoppingCartRepository = shoppingCartRepository;
}
Then, in the test you should mock ShoppingCartRepository, record a behavior for findAllItems() and pass the mock in the constructor of MyService.
#Mock
private ShoppingCartRepository shoppingCartRepositoryMock;
#Test
public void calculateItemsCostInShoppingCart(){
Long cartId = Long.valueOf(123);
// set the dependency
MyService myService = new MyService(shoppingCartRepositoryMock);
// create the mock
Mockito.when(shoppingCartRepositoryMock.findAllItems(cartId))
.thenReturn(createMockedItems());
//action
Long actualCost = myService.calculateItemsCostInShoppingCart(cartId);
// assertion
Assert.assertEquals(expectedCost, actualCost);
}
private List<Item> createMockedItems() { ... }
You can use Rest assured library for test
get Rest assured response Object, and call method for method object of list.
#BeforeClass
public static void init() {
RestAssured.baseURI = "http://localhost";
RestAssured.port = 8080;
}
#Test
public void testUserRegistration() {
Response response =
RestAssured
.given()
.get(URL_LOGIN)
.then()
.assertThat()
.statusCode(200);
Assert.assertThat(200, Matchers.is(200));
Assert.assertThat(response.getStatusCode(), Matchers.is(200));
}

Categories

Resources