Not Able to access getter of object returned from mocked method - spring

TEST METHOD
public void saveDemandCenterCategory() {
String category = "testCategory";
DemandCenterCategoryEntity demandCenterCategoryEntity = new DemandCenterCategoryEntity();
demandCenterCategoryEntity.setId(1l);
demandCenterCategoryEntity.setCategory(category);
AgentEntity agentEntity = new AgentEntity();
agentEntity.setId(11l);
when(agentRepository.findByMobile(anyString())).thenReturn(agentEntity);
when(demandCenterCategoryEntityRepository.save(any(DemandCenterCategoryEntity.class))).
thenReturn(demandCenterCategoryEntity);
assertEquals(demandCenterServiceImpl.saveDemandCenterCategory(anyString(),any()),isNotNull());
}
Method to test
public DemandCenterCategoryEntity saveDemandCenterCategory(#NotEmpty String name,
#NotNull Entitlements entitlements) {
DemandCenterCategoryEntity demandCenterCategoryEntity = new DemandCenterCategoryEntity();
demandCenterCategoryEntity.setCategory(name);
demandCenterCategoryEntity.setUpdatedBy(agentRepository.findByMobile(entitlements.getSubject()).getId());//null pointer
return demandCenterCategoryEntityRepository.save(demandCenterCategoryEntity);
}
Getting Null pointer expression while getting data from mocked method returned data.

It is probably the any() passed as entitlements argument that causes the NPE
By the way you should not use mockito matchers in the method under test

Related

Can this method be tested using mockito?

I am not sure how to test the first method in the service layer with Mockito as it is using the helper method. Below is my failed attempt at a test: I get an InvalidUseOfMatchersException in the second when clause.
Thanks in advance!
#Mock
private EntityRepository EntityRepo;
#InjectMocks
private EntityService EntityService;
public List<DTO> getAllDTOs(){
//first method
return entityRepo.findAll()
.stream()
.map(this::convertEntityToDTO)
.collect(Collectors.toList());
}
//helper method
public DTO convertEntityToDTO(Entity entity) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setMatchingStrategy(MatchingStrategies.LOOSE);
DTO dto = new DTO();
dto = modelMapper.map(entity, DTO.class);
return dto;
}
#Test
public void EntityService_GetAll_ReturnsDTOList() {
when(entityRepo.findAll()).thenReturn(Mockito.anyList());
//the second when clause: when(entityService.convertEntityToDTO(Mockito.any(Entity.class)))
.thenReturn(Mockito.any(DTO.class));
List<DTO>DTOList = entityService.getAllDTOs();
Assertions.assertThat(DTOList).isNotNull();
Mockito#any* methods are actually defined in class ArgumentMatchers and can only be used to match the call arguments when setting up a mock or when verifying calls. All matcher methods return null (but have side-effects of modifying a matcher stack to be able to properly detect and match mocked calls).
For instance, you might do Mockito.when(svc.print(Mockito.anyString()).doNothing() when you don't care about the input or Mockito.verify(svc.print(Mockito.anyString()), Mockito.never()) when you want to verify that the method has never been called.
When setting up your mock, you have to provide a real value in your thenReturn call:
when(entityRepo.findAll()).thenReturn(Collections.emptyList());
when(entityService.convertEntityToDTO(Mockito.any(Entity.class)))
.thenReturn(new DTO());

How to unit test EventListenerProvider onEvent method of Keycloak

EventListenerProvider.java class
#Override
public void onEvent(AdminEvent event, boolean includeRepresentation) {
log.info("Admin Event Occurred:" + toString(event));}`
Util.java class
public static String toString(AdminEvent adminEvent) {
StringBuilder sb = new StringBuilder();
sb.append("operationType=");
sb.append(adminEvent.getOperationType());
...
return sb.toString();
}
Test.java
#Test
void testOnEventAdminShouldLog() {
when(UtilClass.toString(adminEvent)).thenReturn("someString");
sessionEventProvider.onEvent(adminEvent, true);
verify(sessionEventProvider,times(1)).onEvent(adminEvent, true);
}
When I run the test it gives error as below:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
inside when() you don't call method on mock but on some other object.
How to test this method ?
Thanks.

resilience4j circuit breaker change fallback method return type than actual called method return type

I am trying to learn Spring Boot microservices. Now I am trying to implement circuit breaker with resilience4j if any of my called service is off.
If I set the fallback method return type as like the actual method return type than it works fine but I can't show the information that my service is off. Because it then send the response null in object's fields. But if I change the return type to String on actual method and also in fallback then I will not be able to get the object value as JSON.
Is it possible to return as string something like Branch service is down!.. with my fallback method and if OK then get the object value as JSON from actual called method? My attempts are below:
My controller method:
#GetMapping("/getById/{id}")
#CircuitBreaker(name = "default", fallbackMethod = "employeeFallback")
public ResponseModelEmployee getEmployee(#PathVariable("id") Long id) {
return employeeService.findByEmployeeId(id);
}
My fallback method in controller:
public ResponseModelEmployee employeeFallback(Long id, Exception ex) {
return new ResponseModelEmployee();
}
My service method called from controller:
public ResponseModelEmployee findByEmployeeId(Long id) {
ResponseModelEmployee empDetails = new ResponseModelEmployee();
...
Branch branch = restTemplate.getForObject("http://BRANCH-SERVICE/branch/getById/" +
employee.get().getBranchId(),
Branch.class);
...
return empDetails;
}
My desire method as fallback:
public String employeeFallback(Long id, Exception ex) {
return "Branch Service is down";
}
If I set my desire method for fallback then it gives the following error:
java.lang.NoSuchMethodException: class com.example.employee.VO.ResponseModelEmployee class com.example.employee.controller.EmployeeController.employeeFallback(class java.lang.Long,class java.lang.Throwable) at io.github.resilience4j.fallback.FallbackMethod.create(FallbackMethod.java:92) ~[resilience4j-spring-1.7.0.jar:1.7.0] ....
Resilince4j expects the fallback method to have the same return type as of the actual method.
Documentation says:
It's important to remember that a fallback method should be placed in
the same class and must have the same method signature with just ONE
extra target exception parameter).
If there are multiple fallbackMethod methods, the method that has the
most closest match will be invoked, for example:
If you try to recover from NumberFormatException, the method with
signature String fallback(String parameter, IllegalArgumentException
exception)} will be invoked.
You can define one global fallback method with an exception parameter
only if multiple methods has the same return type and you want to
define the same fallback method for them once and for all.
So, you cannot directly change the return type to a different one.
You can try few suggestions:
Add #CircuitBreaker and fallback to the service method.
Change return type of service method and fallback method to Object.
One more way could be , you can keep the return type as it is but add a String type message object to response model ResponseModelEmployee. Then set message string to it during fallback.
Another solution could be to return ResponseEntity from the from the method where rest call is made and in the fallback method use ResponseEntity<?> as response object.
you can use Object as a return type
in my case for example:
#GetMapping("/getUser/{id}")
#CircuitBreaker(name= something , fallbackMethod = "ContactsServiceDown")
public ResponseEntity<User> getDetailsById(#PathVariable(id)){
//some logic
return new ResponseEntity<User>(user , HttpStatus.OK);
}
public ResponseEntity<Object> ContactsServiceDown(int id , Exception e){
//some logic
return new ResponseEntity<Object>("ContactsServersDown", HttpStatus.Forbidden)
}
or in returnType ResponseEntity<> leave the type Field empty, hopefully it may work!

Type casting in spring program

I am facing issue in spring program, the issue is Why type casting is applied in spring application?
below is the program for reference.
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Hello obj= (Hello)context.getBean("hello");
obj.getMessge();
}
}
The getBean(String) method returns an object of the type Object. Since you know that the method you annotated with #Bean(name = "hello") returns an instance of Hello you can safely cast getBean's return value to Hello.
Object getBean(String name) returns an instance of type Object; hence, you must cast it to whatever you expect it to return.
<T> T getBean(String name, Class<T> requiredType) overloaded method can be used alternatively, and it will return the object of type T.
You can change your code as follows:
Hello obj = context.getBean("hello", Hello.class);
and in this case, you will not need to cast the returned object explicitly.

Spring Jackson ObjectMapper Fails to JSON Deserialize While the Unit Test Passes

I've got a class in my Spring web application:
#Value // or #Data Lombok
public class Bar {
private final BigDecimal value;
#JsonCreator
public Bar(double value) {
this.value = BigDecimal.valueOf(value);
}
}
I wrote a unit test which passes:
#Test
void test() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Bar bar = new Bar(12.34);
assertEquals(mapper.readValue("12.34", Bar.class), bar);
}
But when I send a POST to the controller, it fails to deserialize the request body (which is just 12.34 to be deserialized to a Bar instance) with the following error:
JSON parse error: Cannot construct instance of com.example.demo.Bar (although at least one Creator exists): no double/Double-argument constructor/factory method to deserialize from Number value (12.34); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.example.demo.Bar (although at least one Creator exists): no double/Double-argument constructor/factory method to deserialize from Number value (12.34)
If I remove the #Value, it can deserialize it. To make it even more confusing, if I add the constructor (created by #Value) manually, still it works. But if I remove #JsonCreator it again can deserialize it.
What am I missing?
#Jsoncreator should be used in conjunction with #JsonProperty, to specify how to deserialize a JSON object. So if for example you have a rest controller that some JSON like:
{
"value": 123
}
Your constructor should be annotated like such:
#JsonCreator
public Bar(#JsonProperty("value") double value) {
this.value = BigDecimal.valueOf(value);
}
Although this might see redundant, the idea is that this allows for more flexibily in cases were the JSON you intend to deserialize doesn't match the name of your properties.
So for example if the object you are receiving still has a key value, but your class has a property myValue, the following will work:
public class Example {
private final BigDecimal myValue;
#JsonCreator
public Bar(#JsonProperty("value") double myValue) {
this.myValue= BigDecimal.valueOf(myValue);
}
}

Resources