How to test Update method in Java Unit Test - java

I am creating Unit Test for my ServiceImpl methods and I try to create a unit test for update method. However, I am not sure how should I test this method. It returns DTO of corresponding entity, but I have really no idea if I should use #Spy or #Captor. If I set a mock variable and then try to retrieve it and update its value, I will need to retrieve the same record to check its updated value.
I am new in testing and I have not found a proper example for update method. Any help would be appreciated.
public CompanyDTO update(CompanyRequest companyRequest, UUID uuid) {
final Company company = companyRepository.findByUuid(uuid)
.orElseThrow(() -> new EntityNotFoundException(COMPANY));
company.setName(companyRequest.getName());
final Company savedCompany = companyRepository.save(company);
return new CompanyDTO(savedCompany);
}
Update: Finally I make it worked, but I am not sure for some parts. Is there anything missing or redundant in the following test method?
#InjectMocks
private CompanyServiceImpl companyService;
#Mock
private CompanyRepository companyRepository;
#Captor
ArgumentCaptor<Company> companyCaptorEntity;
#Test
public void testUpdate() {
final UUID uuid = UUID.randomUUID();
final CompanyRequest request = new CompanyRequest();
request.setName("Updated Company Name");
final Company company = new Company();
company.setName("Company Name");
when(companyRepository.findByUuid(uuid))
.thenReturn(Optional.ofNullable(company));
//??? Do we need this?
when(companyRepository.save(any())).thenReturn(company);
CompanyDTO result = companyService.update(request, uuid);
Mockito.verify(companyRepository).save(companyCaptor.capture());
Company savedCompany = companyCaptor.getValue();
assertEquals(request.getName(), savedCompany.getName());
}

More importantly than the return type of the update() method, I believe you should test the values of the entity passed to the save() method of your mock repository (I assume you have one).
For this, you can use ArgumentCaptor.
For testing the return logic of your update() method, you can simply assign its result in your test to a response object. You can then compare this object with the values of your input object.
Here is an example of both testing the arguments to the save method of your mock repository and the return of your update method (they should be two different unit tests):
#Test
void test() {
// Arrange
ArgumentCaptor<Entity> entityArgumentCaptor = ArgumentCaptor.forClass(Entity.class);
InputDto inputDto = prepareTestInput();
// Act
ResponseDto responseDto = service.update(inputDto);
verify(repositoryMock, times(1)).save(entityArgumentCaptor.capture());
// Assert
Entity savedEntity = argumentCaptor.getValue();
assertEquals(input.getVariable1(), savedEntity.getVariable1());
// .....
// compare ResponseDto and InputDto too
}

Related

How to test update methods?

I am new in unit testing and use JUnit in my Java (Spring Boot) app. I sometimes need to test update methods, but when I search on the web, there is not a proper example or suggestion. So, could you please clarify me how to test the following update method? I think this may require a different approach than testing void. I also thought that while testing first mocking the record and then update its field and then update. Finally retrieve the record again and compare the updated properties. But I think there may be more proper approach than this inexperienced one.
public PriceDTO update(UUID priceUuid, PriceRequest request) {
Price price = priceRepository
.findByUuid(priceUuid)
.orElseThrow(() -> new EntityNotFoundException(PRICE));
mapRequestToEntity(request, price);
Price updated = priceRepository.saveAndFlush(price);
return new PriceDTO(updated);
}
private void mapRequestToEntity(PriceRequest request, Price entity) {
entity.setPriceAmount(request.getPriceAmount());
// set other props
}
You would need to do something along the following lines:
public class ServiceTest {
#Mock
private PriceRepository priceRepository;
(...)
#Test
public void shouldUpdatePrice() throws Exception {
// Arrange
UUID priceUuid = // build the Price UUID
PriceRequest priceUpdateRequest = // build the Price update request
Price originalPrice = // build the original Price
doReturn(originalPrice).when(this.priceRepository).findByUuid(isA(UUID.class));
doAnswer(AdditionalAnswers.returnsFirstArg()).when(this.priceRepository).saveAndFlush(isA(Price.class));
// Act
PriceDTO updatedPrice = this.service.update(priceUuid, priceUpdateRequest);
// Assert
// here you need to assert that updatedPrice is as you expect according to originalPrice and priceUpdateRequest
}
}
You need to mock the behavior of the class object priceRepository.
So you will have to write something like below to begin :
// priceRepository should be mocked in the test class
Mockito.when(priceRepository.findByUuid(any(UUID.class))).thenReturn(new Price());
So if your only intention is to verify if you called save, then something like this is probably what you are looking for:
#ExtendWith(MockitoExtension.class)
public class ServiceTest {
#Mock
private PriceRepository priceRepository;
#InjectMocks
private Service service;
#Test
public void update() throws Exception {
// Given
Price price = new Price();
price.setUid(UUID.randomUUID());
price.setPriceAmount(100);
when(priceRepository.findByUid(price.getUid()))
.thenReturn(price);
ArgumentCaptor<Price> priceArgument =
ArgumentCaptor.forClass(Price.class);
when(incidentRepository.saveAndFlush(priceArgument.capture()))
.thenAnswer(iom -> iom.getArgument(0));
// When
PriceRequest priceRequest = new PriceRequest();
priceRequest.setPriceAmount(123);
PriceDTO updatedPrice = this.service.update(price.getUid(), priceUpdateRequest);
// Then
assertThat(priceArgument.getValue().getPriceAmount())
.isEqualTo(123);
}
}

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

Mockito verify unit test - Wanted but not invoked. Actually, there were zero interactions with this mock

At first I want to sorry for my english.
I started to make some unit tests (i've never done this before, i'm a new guy in programming).
I have to test simple adding product to database (DynamoDB) method using mockito.verify but I have
"Wanted but not invoked. Actually, there were zero interactions with this mock."
Error and I don't know what to do.
This is my method code (in KitchenService class):
public Product addProduct(Product content) {
ObjectMapper objectMapper = new ObjectMapper();
String mediaJSON = null;
String authorJSON = null;
String productKindsJSON = null;
try {
mediaJSON = objectMapper.writeValueAsString(content.getMedia());
authorJSON = objectMapper.writeValueAsString(content.getAuthor());
productKindsJSON = objectMapper.writeValueAsString(content.getProductKinds());
} catch (JsonProcessingException e) {
logger.log(e.getMessage());
}
Item item = new Item()
.withPrimaryKey("id", UUID.randomUUID().toString())
.with("name", content.getName())
.with("calories", content.getCalories())
.with("fat", content.getFat())
.with("carbo", content.getCarbo())
.with("protein", content.getProtein())
.with("productKinds", productKindsJSON)
.with("author", authorJSON)
.with("media", mediaJSON)
.with("approved", content.getApproved());
Item save = databaseController.saveProduct(PRODUCT_TABLE, item);
logger.log(save + " created");
return content;
}
And this is test code:
#Test
public void addProduct() throws Exception {
KitchenService instance = mock(KitchenService.class);
Product expectedProduct = new Product();
expectedProduct.setName("kaszanka");
expectedProduct.setCalories(1000);
expectedProduct.setFat(40.00);
expectedProduct.setCarbo(20.00);
expectedProduct.setProtein(40.00);
expectedProduct.setProductKinds(Collections.singletonList(ProductKind.MEAT));
expectedProduct.setApproved(false);
Author expectedAuthor = new Author();
expectedAuthor.setId("testID");
expectedAuthor.setName("Endrju Golota");
expectedProduct.setAuthor(expectedAuthor);
Media expectedMedia = new Media();
expectedMedia.setMediaType(MediaType.IMAGE);
expectedMedia.setName("dupajasia");
expectedMedia.setUrl("http://blabla.pl");
expectedProduct.setMedia(expectedMedia);
verify(instance, times(1)).addProduct(expectedProduct);
}
This is what I got after test:
Wanted but not invoked:
kitchenService.addProduct(
model.kitchen.Product#a0136253
);
-> at service.kitchen.KitchenServiceTest.addProduct(KitchenServiceTest.java:80)
Actually, there were zero interactions with this mock.
Can someone tell me what im doing wrong?
What you should mock and verify is the databaseController dependency:
#Test
public void addProduct() throws Exception {
KitchenService instance = new KitchenService(); // you should create the class under test
DatabaseController controllerMock = mock(DatabaseController.class); // mock the controller
instance.setController(controller); // inject the mock
...
// Act
instance.addProduct(expectedProduct);
// Assert
verify(controller).saveProduct(Mockito.eq(PRODUCT_TABLE), Mockito.any(Item.class));
}
You should verify that the database is called within the service.. checking that it was invoked with any Item object should be enough.
Mocking is a tool that you only use for dependencies of the class that is being tested.
It appears that your test does not care about the Author, Media, and Product objects,
these are just dependencies of the method you want to test;
mock them.
Organization will greatly help your test;
do something like this:
public class TestKitchenService
{
private static String VALUE_PRODUCT_NAME = "VALUE_PRODUCT_NAME";
... use constants for other values as well. The value of the constant does not matter.
#InjectMocks
private KitchenService classToTest;
private InOrder inOrder;
#Mock
private Author mockAuthor;
#Mock
private DatabaseController mockDatabaseController;
#Mock
private Logger mockLogger;
#Mock
private Media mockMedia;
#Mock
private Product mockProduct;
#After
public void afterTest()
{
inOrder.verifyNoMoreInteractions();
verifyNoMoreInteractions(mockAuthor);
verifyNoMoreInteractions(mockDatabaseController);
verifyNoMoreInteractions(mockLogger);
verifyNoMoreInteractions(mockMedia);
verifyNoMoreInteractions(mockProduct);
}
#Before
public void beforeTest()
{
MockitoAnnotations.initMocks(this);
doReturn(mockAuthor).when(mockProduct).getAuthor();
doReturn(mockMedia).when(mockProduct).getMedia();
doReturn(VALUE_PRODUCT_NAME).when(mockProduct).getName();
doReturn(Collections.singletonList(ProductKind.MEAT)).when(mockProduct).getProductKinds();
... doReturns for the other product values.
inOrder = inOrder(
mockAuthor,
mockDatabaseController,
mockLogger,
mockMedia,
mockProduct);
ReflectionTestUtils.setField(
classToTest,
"databaseController",
mockDatabaseController);
ReflectionTestUtils.setField(
classToTest,
"logger",
mockLogger);
}
#Test
public void addProduct_success()
{
final Product actualResult;
actualResult = classToTest.addProduct(mockProduct);
assertEquals(
mockProduct,
actualResult);
inOrder.verify(mockProduct).getMedia();
inOrder.verify(mockProduct).getAuthor();
inOrder.verify(mockProduct).getProductKinds();
inOrder.verify(mockProduct).getName();
... inOrder.verify for the other product values.
inOrder.verify(mockDatabaseController).saveProduct(
eq(PRODUCT_TABLE),
any(Item.class));
}
}
The only things that should be mocked -- if anything -- are the ObjectMapper and databaseController. One only mocks collaborator objects, and almost never the system/class under test (very rare cases exist for "spying" on the SUT). And depending on what the ObjectMapper is and how transparent it's operation is, you may not really want to even mock that. Furthermore, as your implementation code is written instantiating the ObjectMapper by directly calling a constructor, you can't even mock it.
While I love the use of Mockito and mock objects, sometimes it is worthwhile to simply test with as many real objects as possible. This is especially true when your collaborators are simple, straightforward, have no side effects, and don't require complex initialization or setup. Only use mocks when it simplifies the test setup or verification.

How to Correctly mock an object with Mockito

I am trying to test the ClientDetails class below and trying to learn JUnit and Mockito at the same time.
// this is the class I'm trying to test
public class ClientDetails {
#Autowired private IApplicantService<Applicant> applicantService;
#Autowired private ClientDetailsHelpers helpers;
public FullClientDetails getClientDetails(String businessId, boolean isNewClient) {
FullClientDetails fcd = new FullClientDetails();
ClientParams params = new ClientParams();
params.setBusinessId(businessId);
ApplicantId ai = applicantService.retrieveApplicantIdFromBusinessId(params);
Long applicantId = ai.getApplicantId();
params.setApplicantId(applicantId);
Applicant applicant = applicantService.retrieveApplicantDetailsByHerdNumber(params);
helpers.validateRetrievedApplicant(applicant, isNewClient, businessId);
fcd.setApplicant(applicant);
// more method calls that get and assign objects to the fcd object
return fcd;
}
}
// ClientDetailsHelpers.java method that throws exception
public void validateRetrievedApplicant(Applicant applicant, boolean isNewClient, String businessId) {
if (applicant.getApplicantId() == null && !isNewClient) {
throw new ValidationSearchException(businessId);
}
}
// test class
#RunWith(MockitoJUnitRunner.class)
public class ClientDetailsTest {
private final static String BUSINESS_ID = "A1234567";
private final static Long APPLICANT_ID = null;
#InjectMocks
ClientDetails clientDetails;
#Mock ApplicantServiceImpl applicantService;
#Mock ClientDetailsHelpers helpers;
private ApplicantParams params;
private Applicant applicantWithInvalidId = new Applicant();
ApplicantId applicantId = new ApplicantId(APPLICANT_ID, BUSINESS_ID);
#Before
public void before(){
applicantWithInvalidId.setApplicantId(null);
}
#Test(expected = ValidationSearchException.class)
public void testGetFullApplicationDetails(){
when(applicantService.retrieveApplicantIdFromBusinessId(Mockito.any(ApplicantParams.class))).thenReturn(applicantId);
when(applicantService.retrieveApplicantDetailsByHerdNumber(Mockito.any(ApplicantParams.class))).thenReturn(applicantWithInvalidId);
FullClientDetails fcd = clientDetails.getFullClientDetails(BUSINESS_ID , false);
}
}
In my test class I create some mock objects, including an ApplicantId object to be returned when applicantService.retrieveApplicantIdFromBusinessId() is called and Applicant object with is applicantId attribute set to null to be return when applicantService.retrieveApplicantDetailsByHerdNumber() is called.
The function ClientDetailsHelper.validateRetrievedApplicant() should throw an exception if Applicant.getApplicantId() returns a null and if the boolean isNewClient is set to false however it doesn't seem to be happening in the test, it throws no exception and the #Test fails.
My best guess is that I am not using when().thenReturn() to correctly return the Applicant and ApplicantId objects I have created and instead another Applicant object is getting passed to validateRetrievedApplicant() and returning and applicantId of 0 when it gets to the validation method.
Any suggestions? Thanks!
Your code is not throwing an exception because there is nowhere in the code you are testing that throws that exception. I assume your exception is thrown within the ClientDetailsHelpers class but you are mocking this class so it will not call the actual code and so no exception will be thrown.
You need to think about what you want to test. Do you want to test the ClientDetails class in isolation as a unit? In which case you don't need to worry about the exception being thrown since its not part of the functionality of that class.
The second option is that you want to do more of an integration test where you pull in an actual ClientDetailsHelpers class but in order to do this you will need to include some configuration in your test to make sure that this bean is available to the test Spring context. You can do this using a Spring4JunitRunner instead of the Mockito one and then pulling in a configuration class with a component scan for your ClientDetailsHelpers class using the #ContextConfiguration(MyConfig.class) annotation on your test class where MyConfig is the relevant Spring config class.

JUnit test cases using mockito for Rest API

I am new to Mockito framework , I have a rest APi that connects my application to jasper server and do report related operations.I want to write junit test cases for rest API using mockito framework.
here i have class called Repositoryclient , Its constructor have instance of JasperServerInfo DAO class.
public class RepositoryClient {
public RepositoryClient(ServerInfo serverInfo) {
this.info = serverInfo;
try {
Session = Client.authenticate(info.username.trim(), info.password.trim());
}
catch (Exception e) {
}
}
public void Templates() { //this method brings list of present report in jasper server repository
try {
OperationResult<...> result = ....;
} catch (Exception e) {
INodeProcessor.logger.warn(e.toString());
throw Error.REPORT_TEMPLATE_LIST_ERROR.with();
}
}
So how to write JUnit test cases using mockito for this class please guide me through. Thank you in advance.
Well, the code could be improved to make it actually testable...
At the moment, there is no really good way to write unit tests for your code, since the constructor creates a JasperserverRestClient without any chance to change it. The least you can do is add another constructor (may be package access) to allow another JasperserverRestClient to be used. (Alternatively you could think about using a Factory pattern. but this might be to complicated.)
Then you could mock that...
JasperserverRestClient jasperServerClient = Mockito.mock( JasperserverRestClient.class );
RestClientSession session = Mockito.mock( RestClientSession.class );
Mockito.when( jasperServerClient.authenticate( "x", "y")).thenReturn( session );
RepositoryClient repositoryClient = new RepositoryClient(jasperServerClient);
This would at least allow you to test, that authenticate is called with the correct parameters via Mockito.verify.
Also it would allow you to test that the listTemplates method calls the session with the correct parameters (of course you'll need to so some more mocking there).
An additional constructor, assuming your tests are in the same package, would look like this:
RepositoryClient(JasperserverRestClient httpRestClient, JasperServerInfo serverInfo) {
this.info = serverInfo;
this.httpRestClient = httpRestClient;
try {
restClientSession = httpRestClient.authenticate(info.username.trim(), info.password.trim());
}
catch (Exception e) {
INodeProcessor.logger.warn(e.toString());
throw Error.REPOSITORY_CLIENT_ERROR.with();
}
}
This way you can inject a mocked instance of your JasperserverRestClient into your object.
A test of your listTemplates method would (addtionally) look like this...
X resourcesService = Mockito.mock( X.class ); // No clue what the resourcesService() method is supposed to return, fill that in here
Mockito.when ( restClientSession.resourcesService() ).thenReturn ( resourcesService );
...This will allow the part restClientSession.resourcesService() to work. Next...
Y resources = Mockito.mock( Y.class ); // Same thing here, don't know what resources() should return, insert that class here
Mockito.when( resourcesService.resources()).thenReturn ( resources );
This will allow the resources() call to work.
Next we do some trickery:
Mockito.when( resources.parameter( Mockito.anyString(), Mockito.anyString()).thenReturn(resources); // assuming that ResourceSearchParameter constant is a String
This will allow the parameter() calls to work by returning the same resources() object.
And so on... You will need to when(...).thenReturn(...) the search method to return a OperationResult<ClientResourceListWrapper>, etc. but that's the same stuff as above.
And in the end, we could verify that the methods were called with the right parameters...
Mockito.verify( resources, Mockito.times(1)).parameter(ResourceSearchParameter.FOLDER_URI, info.reportDirectory);
Mockito.verify( resources, Mockito.times(1)).parameter(ResourceSearchParameter.RECURSIVE, "false"
Mockito.verify( resources, Mockito.times(1)).search();
getting started example that i have :
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
#Test(priority = 31, groups = "success")
public void mockExample() {
Category category1 = mock(Category.class);
when(category1.getName()).thenReturn("Yess!!!");
System.out.println(category1.getName());
}
will print:"Yess!!!"
you can read from here :
http://examples.javacodegeeks.com/core-java/mockito/mockito-hello-world-example/
#RunWith(SpringJUnit4ClassRunner.class)
public class UserControllerTest {
#InjectMocks
private UserController userController;
#Mock
private RequestAttributes attrubutes;
#Mock
private UserService userService;
private MockMvc mockMvc;
#Before
public void setup() {
RequestContextHolder.setRequestAttributes(attrubutes);
this.mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
}
#Test
public void getUserinfoDetails() {
String userId = "123";
String userName = "Test145";
List<UserDto> userDtoList = new ArrayList<>();
Mockito.when(userService.getAllUserInfo()).thenReturn(userDtoList);
Assert.assertNotNull(userController.getUserinfo());
Assert.assertNotNull(userDtoList);
Assert.assertNotNull(userId);
Assert.assertNotNull(userName);
}
#Test
public void getUserByIdDetails() {
String userId = "123";
UserDto userDto = new UserDto();
Mockito.when(userService.getUserByUserId(userId)).thenReturn(userDto);
Assert.assertNotNull(userController.getUserById(userId));
Assert.assertNotNull(userDto);
Assert.assertNotNull(userId);
}
}
===========================================================================
for reference use below link:(step by step explanation)
https://www.youtube.com/watch?v=yGLOexeJfKA&t=17s

Categories

Resources