I have the following service method:
public CommandDTO update(UUID uuid, EmployeeRequest request) {
final List<Product> productList = productRepository
.findAllByUuidOrderByOrderNumber(uuid);
final List<UUID> uuidList = request.getUuidList();
for (int i = 0; i < uuidList.size(); i++) {
Product product = productList.get(i);
product.setOrderNumber(i + 1);
// how can I get the product value in this line?
}
return CommandDTO.builder().uuid(uuid).build();
}
Normally, I use ArgumentCaptor in order to get values passing to repository or service. Howevcer, in this example, the product value that I want to get after product.setOrderNumber(i + 1); is not passing service or repository. For this reason I cannot get it. I am not sure if it would be possible using #Spy or doAnswer, but as far as I know, these methods cannot be used as the value is not passing to service or repo. Any idea?
You can mock you repository to return list of mock's:
public test() {
Product product1 = mock(Product.class);
Product product2 = mock(Product.class);
List list = Arraylist();
list.add(product1);
list.add(product2);
when(productRepositoryMock.findAllByUuidOrderByOrderNumber(uuid))
.thenReturn(list)
when(product1).setOrderNumber(captor.capture)
In this case you can use ArgumentCaptor here, but I belive it's redundant in this case, and simple verify call will be enough
service.update(.....);
verify.(product1).setOrderNumber(value);
The product variable comes from productList, which in turn comes from the repository.findAllByUuidOrderByOrderNumber() method. So if you mocked your repository, you could write something like this:
Product givenProduct = new Product();
UUID givenUUID = UUID.randomUUID();
// Create an EmployeeRequest with a `uuidList`
EmployeeRequest givenRequest = new EmployeeRequest(/* TODO */);
// Use Mockito to return a `productList` you choose
// This uses a static import of `Mockito.when()`
when(productRepository.findAllByUuidOrderByOrderNumber(givenUUID)).thenReturn(List.of(givenProduct));
service.updateRequest(givenUUID, givenRequest);
Theoretically you could even return a mocked product in the test logic above, but I suggest using a real Product object.
And now whatever happens to that product, can be asserted within your test.
For example:
// `givenProduct` is element 0, and thus will get an orderNumber of 1
assertThat(givenProduct.getOrderNumber()).isEqualTo(1);
Related
I have the following method in my Java app:
public List<UUID> recursiveMethod(UUID productUuid) {
Set<UUID> productUuidSet = new HashSet<>();
productUuidSet.add(productUuid);
List<Product> subProducts = productRepo.getSubProducts(productUuid);
for (Product subProduct : subProducts) {
final UUID subProductUuid = subProduct.getProductUuid();
productUuidSet.add(subProductUuid);
productUuidSet.addAll(recursiveMethod(subProductUuid));
}
return new ArrayList<>(productUuidSet);
}
As far as I know, recursive method keep each call result recursively. And, when calling the recursive method via productUuidSet.addAll(recursiveMethod(subProductUuid));, it creates a new HashSet, but as it returns the value inside the HashSet, I would be able to keep it in productUuidSet after recursive call.
So, what is wrong with this method? If there is a problem, how can I retain productUuidSet value by adding result after each recursive call?
If I understand your question, you want to keep the set rather than creating new set each time?
This should work:
public List<UUID> recursiveMethod(UUID productUuid) {
Set<UUID> productUuidSet = new HashSet<>(); // or LinkedHashSet if order matters
recursiveMethod0(productUuidSet, productUuid);
return new ArrayList<>(productUuidSet);
}
private void recursiveMethod0(Set<UUID> productUuidSet, UUID productUuid) {
productUuidSet.add(productUuid);
List<Product> subProducts = productRepo.getSubProducts(productUuid);
for (Product subProduct : subProducts) {
recursiveMethod0(productUuidSet, subProduct.getProductUuid());
}
}
TL;DR: simply pass the set instead of recreating it each time.
I simplified your insertion code: productUuidSet.add(subProductUuid); is already done by the recursive function.
Beginner here at unit testing. Following is the method to be tested -
public ListBeneficiaryResponseDTO getBeneficiaryOfMerchants(Long merchantId, Integer page, Integer pageSize,
String sortDirection, String sortField) {
LOGGER.info("Inside getBeneficiaryOfMerchants method");
// default we are setting to added on desc sort
Sort sort = Sort.by(Sort.Direction.DESC,"addedOn");
if(sortField != null && sortDirection != null) {
sort = Sort.by(Sort.Direction.fromString(sortDirection),sortField);
}
Pageable pageRequest = PageRequest.of(page-1, pageSize, sort);
Page<Beneficiary> pageOfBeneficiaries = beneficiaryRepository.findAllByMerchantId(merchantId, pageRequest);
List<BeneficiaryResponseDTO> benResonseDtoList = new ArrayList<BeneficiaryResponseDTO>();
for( Beneficiary ben: pageOfBeneficiaries.getContent()) {
benResonseDtoList.add(this.getBeneficiaryResponseDTO(ben));
}
ListBeneficiaryResponseDTO formattedListBen = new ListBeneficiaryResponseDTO(pageOfBeneficiaries.getTotalPages(),pageOfBeneficiaries.getTotalElements(),pageOfBeneficiaries.getNumber(),benResonseDtoList);
return formattedListBen;
}
In order to write tests, I thought, what can this method do wrong, given the underlying method calls work fine.
Well, I am not sure, but may be some error in putting the elements into the list.
So, I thought writing a test to ensure that the expected number of elements are present in the list benResonseDtoList.
Following is what I tried -
#Test
public void testGetBeneficiariesOfMerchant() throws Exception {
Long merchantId = 2l;
List<Beneficiary> beneficiaryList = new ArrayList<Beneficiary>();
beneficiaryList.add(getBeneficiaryDto());
beneficiaryList.add(getBeneficiaryDto());
Page<Beneficiary> beneficiaries = new PageImpl<Beneficiary>(beneficiaryList); //But I am not sure how many entries are there in the page created.
Mockito.when(beneficiaryRepository.findAllByMerchantId(any(),any())).thenReturn(beneficiaries);
KeyManager keyManager = Mockito.mock(KeyManager.class);
ListBeneficiaryResponseDTO list = beneficiaryService.getBeneficiaryOfMerchants(merchantId,1,2, "DESC","addedOn");
If there were a clear correlation between the number of elements in beneficiaryList and the entries in pageOfBeneficiaries, I could test that.
If I understand your question correctly you want to know the testing scenarios for getBeneficiaryOfMerchants() function given underlining functions are working correctly.
For a given
merchantId, page, pageSize, sortDirection, sortField
ListBeneficiaryResponseDTO would be fixed, let's call this ListBeneficiaryResponseDTO expectedList (you have to construct it as you already know the correct output)
So you should be comparing the following:-
Actual Output:
ListBeneficiaryResponseDTO actualList = beneficiaryService.getBeneficiaryOfMerchants(merchantId,1,2, "DESC","addedOn");
Expected Output:
ListBeneficiaryResponseDTO expectedList(already defined above)
Comparing both the outputs:-
Compare field by field actualList & expectedList
Override the Equals method of the ListBeneficiaryResponseDTO class(or you can use lombok.EqualsAndHashCode to avoid boilerplate code) and do the following:-
assertEquals(**actualList**, **expectedList**)
I'm making a test for a service with a mock.
The problem is to create and inject instance directly from the class to test.
The source is shown below.
public OrderOutDTO createOrder(OrderSessionDTO orderSessionDTO) {
Order order = orderRepository.save(new Order(orderSessionDTO));
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
CreateOrderReqDTO createOrderReqDTO = mock(CreateOrderReqDTO.class);
createTrace(order, callServiceOrder.getData().getReceipt().getTransactionHash(), Trace.PUBLIC);
return new OrderOutDTO(order, null);
}
and test source is shown below.
#Test
public void createOrder() {
// given
CallService callService = mock(CallService.class);
CreateOrderResDataDTO createOrderResDataDTO = mock(CreateOrderResDataDTO.class);
// when
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
// then
assertThat(order, is(Matchers.notNullValue()));
assertThat(order.getOrder(), is(Matchers.notNullValue()));
assertThat(order.getOrder().getReceiver().getName(), is("test"));
}
I thought this test would finish well. But in the code below, it returned null and failed.
// callService.createOrder(new CreateOrderReqDTO(order)) return null
CreateOrderResDTO callServiceOrder = callService.createOrder(new CreateOrderReqDTO(order));
It doesn't seem to recognize it because the service injects a new instance. I want the mock data returned. What should I do?
In the following line you're mocking behavior on createOrderReqDTO as param:
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
whereas further, you're passing some other object:
OrderOutDTO order = orderService.createOrder(orderSessionDTO);
This behavior is not recognized, you would have to pass the same thing you mocked before.
I found it myself!
I use argumentMatchers.
when(callService.createOrder(createOrderReqDTO)).thenReturn(createOrderResDTO);
to
when(callService.createOrder(any())).thenReturn(createOrderResDTO);
thank you.
New to junit test case and want to know the test case for my code here
without hardcoding values.
My code is
public JSONObject getListOfAllForms() {
List<Forms> forms = FormName.getInstance().getformList();
int totalNumberOfforms = 0;
List<String> formIds = new ArrayList<String>();
try {
for (int i = 0; i < forms.size(); i++) {
form formOb = forms.get(i);
formIds.add(formOb.getformId());
totalNumberOfforms = forms.size();
}
} catch (Exception e) {
e.printStackTrace();
}
JSONObject formsListObject = new JSONObject();
formsListObject.put("formIds", formIds);
formsListObject.put("totalNumberOfforms", totalNumberOfforms);
return formsListObject;
}
My controller code is:
#RequestMapping(value = "/new/getforms/{formid}", method = RequestMethod.GET)
public JSONObject getFormByFormId(#PathVariable("formid") String formid) {
return newFormName.getformByformId(formid);
}
If you want to test getListOfAllForms Your problem is basically this line...
List<Forms> forms = FormName.getInstance().getformList();
This line couples your FormName hard into your method. This is bad.
A better way would be to provide the FormName instance when instantiating your class, for example, let's assume the name of your class was MyClass..
private FormName formName;
public MyClass(FormName formName) {
this.formName = formName;
}
This can be used via Spring or manually. Via Spring your FormName instance just needs to be a bean, then you can add #Autowired to the constructor if MyClass itself is a bean.
What is the advantage now? Easy, for a test case, you can now do the simple thing...
public void someGreatTestName() {
FormName formName = ...; // either create a new, fake one or mock one (see below)
JSONObject object = new MyClass(formName).getListOfAllForms();
// now test that the object is correct
}
Doing this means you can inject a fake or mock FormName there, which will return the data you want for the test and so remove the need to have an actual "live" FormName there. In other words, you can fake/mock the dependency to the FormName. This way, your test uses test data and you don't have to hardcode the live values there.
Mocking can be done easily via Mockito, for example, I suggest giving it a try, but in this case, simply creating a new "fake" FormName may suffice.
My test shouldn't pass. I should receive an error at row #2, because I put a wrong value new Long(0) at row #1.
Please tell me where is my mistake.
Thanks.
#Test
public void getPersonListByOtdelIdTest() {
Long otdelId = new Long(454);
ArgumentCaptor<Long> argumentOtdelId = ArgumentCaptor.forClass(Long.class);
SessionFactory mockedSessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
Query query = mock(Query.class);
PersonDAOImpl personDAO = new PersonDAOImpl(mockedSessionFactory);
when(mockedSessionFactory.getCurrentSession()). thenReturn(session);
when(session.createQuery("FROM Person P where P.otdel.otdelId = :otdelId")).thenReturn(query);
#1--> when(query.setParameter("otdelId", new Long(0))).thenReturn(query);
when(query.list()).thenReturn(persons);
List<Person> expectedPersons = personDAO.getPersonListByOtdelId(otdelId);
verify(mockedSessionFactory).getCurrentSession();
verify(session).createQuery("FROM Person P where P.otdel.otdelId = :otdelId");
verify(query).setParameter(eq("otdelId"), argumentOtdelId.capture());
verify(query).list();
#2--> assertEquals(otdelId, argumentOtdelId.getValue());
assertTrue(expectedPersons.containsAll(persons));
}
public class PersonDAOImpl implements PersonDAO {
public List<Person> getPersonListByOtdelId(Long otdelId) {
Query query = sessionFactory.getCurrentSession().createQuery("FROM Person P where P.otdel.otdelId = :otdelId");
query.setParameter("otdelId", otdelId);
List<Person> listPersons = query.list();
return listPersons;
}
}
I don't see why you would expect an assertion failure at #2. Your test passed in 454 (as a Long) into getPersonListByOtdelId(), so that will be passed to query.setParameter(). The when() code in #1 is essentially a no-op, because there is no call to query.setParameter() with those values, but Mockito won't complain if the call specified in a when() never happens, and the code under test doesn't check the return value, so there's no exception.
In any case, you don't need an ArgumentCaptor; you just need to have Mockito verify that the correct value was passed to setParameter()
In fact, many of verify calls aren't needed you could just do this:
#Test
public void getPersonListByOtdelIdTest() {
Long otdelId = 454L; // or = Long.valueOf(454); don't use new Long
SessionFactory mockedSessionFactory = mock(SessionFactory.class);
Session session = mock(Session.class);
Query query = mock(Query.class);
when(mockedSessionFactory.getCurrentSession()).thenReturn(session);
when(session.createQuery("FROM Person P where P.otdel.otdelId = :otdelId"))
.thenReturn(query);
when(query.setParameter("otdelId", otdelId)).thenReturn(query);
when(query.list()).thenReturn(persons);
PersonDAOImpl personDAO = new PersonDAOImpl(mockedSessionFactory);
List<Person> result = personDAO.getPersonListByOtdelId(otdelId);
verify(query).setParameter("otdelId", otdelId);
assertEquals(result, persons);
}
You don't need to verify that getCurrentSession() is called, because if it wasn't the code under test wouldn't get a session. You don't need to verify that the correct query was passed to createQuery(), because of the code under test used a different query, Mockito wouldn't return a mock query (unless, of course, you use RETURNS_MOCKS).
That all being said, I don't think the above test is a good test. The test is almost exactly mirroring the code, and it doesn't verify that the code will work. In other words, it's a change detector test.
I wouldn't use a mocking framework to test PersonDaoImpl. Instead, I would write a test that started an in-memory database, using a schema file that is also used to create the actual table in production.
I would use a mock for tests for a class that depends on PersonDAO.