Mockito throwing a NullpointerException on using a mock - java

I'm trying to create test cases for a webservice but I'm getting nullpointerexception. This is the web service:
#Path("friendservice")
public class FriendWebService {
private static final Logger logger = Logger.getLogger(FriendWebService.class);
#EJB
private FriendRequestServiceInterface friendRequestService;
#GET
#Path("friendrequest")
#Produces(MediaType.TEXT_PLAIN)
public String createFriendRequest(
#Context HttpServletRequest request) {
logger.info("createFriendRequest called");
String result = "false";
User user = (User) request.getSession().getAttribute("user");
User otherUser = (User) request.getSession().getAttribute("profileuser");
if ((user != null) && (otherUser != null)) {
logger.info("Got two users from session, creating friend request.");
if (friendRequestService.createFriendRequest(user, otherUser)) {
result = "true";
}
}
return result;
}
}
This is my test class:
public class FriendWebServiceTest {
#Mock
FriendRequestServiceInterface FriendRequestService;
#Mock
Logger mockedLogger = mock(Logger.class);
#Mock
HttpServletRequest mockedRequest = mock(HttpServletRequest.class);
#Mock
HttpSession mockedSession = mock(HttpSession.class);
#Mock
User mockedUser = mock(User.class);
#Mock
User mockedOtherUser = mock(User.class);
#InjectMocks
FriendWebService friendWebService = new FriendWebService();
#Before
public void setUp() throws Exception {
}
#Test
public void testCreateFriendRequest() throws Exception {
when(mockedRequest.getSession()).thenReturn(mockedSession);
when(mockedSession.getAttribute("user")).thenReturn(mockedUser);
when(mockedSession.getAttribute("profileuser")).thenReturn(mockedOtherUser);
when(FriendRequestService.createFriendRequest(mockedUser, mockedOtherUser)).thenReturn(true);
assertTrue(friendWebService.createFriendRequest(mockedRequest) == "true");
}
The NullPointerException occurs at "when(FriendRequestService.createFriendRequest(mockedUser, mockedOtherUser)).thenReturn(true);"
What am I doing wrong?

You are chaining method calls on your mocked instance:
#Mock
HttpServletRequest mockedRequest = mock(HttpServletRequest.class);
First of all, you do not need to do both, either use the #Mock annotation or the mock method. Like this, you first assign a Mock and then replace this instance with another mock. I recommend the annotation as it adds some context to the mock such as the field's name. This might already cause your NullPointerException as you however never activate the annotations by calling:
MockitoAnnotations.initMocks(this);
as you do not consequently mock all instances with both measures so far. However, even doing so will further result in your exception, so let's move ahead.
Within friendWebService.createFriendRequest(mockedRequest) you call:
User user = (User) request.getSession().getAttribute("user");
User otherUser = (User) request.getSession().getAttribute("profileuser");
where you call a method on two mocks for which you did not specify any behavior. These mocks do by default return null. You need to specify behavior for this such as:
when(request.getSession()).thenReturn(myMockedSession);
before performing this chained call. Based on this, you can then specify how to react to calls on this mocked instance such as returning your user mocks.

Instead of calling initMocks, You probably need to annotate with #RunWith(MockitoJUnitRunner.class) to your FriendWebServiceTest class.

You can also try adding #RunWith(MockitoJUnitRunner.class) or #ExtendWith(MockitoExtension.class) annotations to your FriendWebServiceTest class for JUnit4 and JUnit5 respectively.

Related

Spring Boot / Mockito: Mocking RestTemplate but Response Always Null

I'm having problems mocking the response object of my Test Class when using Mockito. I'm trying to test an exception, for this I need one of the attributes of the Class that returns from the POST request. I've successfully mocked the RestTemplate but my when().thenReturn() is not returning anything and I'm getting a null pointer exception at the "if" validation. If anyone could help me on this problem I would be very grateful.
Here is my Service Class:
#Service
public class CaptchaValidatorServiceImpl implements CaptchaValidatorService{
private static final String GOOGLE_CAPTCHA_ENDPOINT = "someEndpoint";
private String stage;
private String captchaSecret;
private RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
#Override
public void checkToken(String token) throws Exception{
MultiValueMap<String,String> requestMap = new LinkedValueMap<>();
requestMap.add("secret", captchaSecret);
requestMap.add("response", token);
try{
CaptchaResponse response = restTemplate.postForObject(GOOGLE_CAPTCHA_ENDPOINT,
requestMap, CaptchaResponse.class);
if(!response.getSuccess()){
throw new InvalidCaptchaTokenException("Invalid Token");
}
} catch (ResourceAccessException e){
throw new CaptchaValidationNotPossible("No Response from Server");
}
}
private SimpleClientHttpRequestFactory getClientHttpRequestFactory(){
...
}
}
And here is my Test Class:
#SpringBootTest
public class CaptchaValidatorTest{
#Mock
private RestTemplate restTemplate;
#InjectMocks
#Spy
private CaptchaValidatorServiceImpl captchaValidatorService;
private CaptchaResponse captchaResponse = mock(CaptchaResponse.class);
#Test
public void shouldThrowInvalidTokenException() {
captchaResponse.setSuccess(false);
Mockito.when(restTemplate.postForObject(Mockito.anyString(),
ArgumentMatchers.any(Class.class), ArgumentMatchers.any(Class.class)))
.thenReturn(captchaResponse);
Exception exception = assertThrows(InvalidCaptchaTokenException.class, () ->
captchaValidatorService.checkToken("test"));
assertEquals("Invalid Token", exception.getMessage());
}
}
In my opinion it could be a problem with ArgumentMatchers.
Method postForObject require parameters as String, MultiValueMap(or parent) and Class, but you set in Mockito.when: anyString() (correct), any(Class.class) (but MultiValueMap is passed - probably incorrect) and any(Class.class) (correct).
Try use:
Mockito.when(restTemplate.postForObject(ArgumentMatchers.any(String.class),
ArgumentMatchers.any(MultiValueMap.class), ArgumentMatchers.any(Class.class)))
.thenReturn(captchaResponse);
EDIT:
It seems to me that the CaptchaResponse in the test is unnecessarily a mock:
private CaptchaResponse captchaResponse = mock(CaptchaResponse.class);
but if You want this in that way, I think u need to replace:
captchaResponse.setSuccess(false);
to something like:
Mockito.when(captchaResponse.getSuccess()).thenReturn(false);

How to unit test a cachable method

I am using Spring Cache.
I have a Spring controller and as part of the method responsible for that GET request, I have annotated it with #Cacheable(value = "customer", key = "#accountId"). In that method, it calls an API and does some business logic and then returns a DTO. With the cache annotation in place, I'm expecting on the first execution of this code will run normally but any subsequent calls later, it'll fetch the result from the cache.. that's correct right?
I'm writing a unit test to verify that the API was called once despite mocking multiple requests being sent to that controller. But the problem is that it keeps on calling the API multiple times and not calling the cache.
Unit test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebMvcTest(controllers = CustomerController.class, secure = false)
public class CustomerControllerTest {
private static final String ACCOUNT_ID = "1111";
#MockBean
private CustomerService customerService;
#MockBean
private CustomerPortAPI customerPortAPI;
#Autowired
MockMvc mockMvc;
#Before
public void setUp(){
when(customerService.getStatus(any())).thenReturn("test");
when(customerPortAPI.getAccount(any())).thenReturn(Account.builder().build());
}
#Test
public void shouldReturnCustomerDTOt() throws Exception {
when(customerService.Status(any())).thenReturn("test");
when(customerPortAPI.getAccount(ACCOUNT_ID)).thenReturn(Account.builder().accountId(ACCOUNT_ID).build());
mockMvc.perform(get("/customer/{accountId}/status", ACCOUNT_ID)
.accept(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("status").value(customer.NOT_REQUIRED.name()));
mockMvc.perform(get("/customer/{accountId}/status", ACCOUNT_ID)
.accept(APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("status").value(customer.NOT_REQUIRED.name()));
verify(customerPorAPI, times(1)).getAccount(ACCOUNT_ID);
}}
Controller Method:
#Cacheable(value = "statusEligibility", key = "#customerId")
#GetMapping
public CustomerStatusDTO getCustomerStatus(#PathVariable String customerId) {
Customer customer = cusomterPort.getAccount(customerId);
Status status = service.getStatus(customer);
if (status.equals(Cons.REQUIRED)) {
/.../
} else {
/.../
}

how to fetch response from requestContext.abortwith() method

Class Permission implements ContainerRequestContext
{
#context
HttpServletRequest servletRequest;
public void filter(ContainerRequestContext containerRequestContext) throws IOException
{
String Path=servletRequest.getPathInfo;
int id=containerRequestContext.getId;
if(id==null){
containerRequestContext.abortWith(new ServerResponse(ExceptionUtil.getErrorMessageObject(...),errorCode,new Header<Object>()));
}
}
}
For the Testing purpose,
How to fetch the errorCode set inside the ServerResponse object when we are setting the id=null.
#RunWith(MockitoJUnitRunner.class)
class Test {
#InjectMocks
private Permission permission;
#Mock
private HttpServletRequest servletRequest;
#Mock
private ContainerRequestContext containerRequestContext;
#Test
public void test()
{
when(servletRequest.getPathInfo()).thenReturn("/getid");
when(containerRequestContext.getId()).thenReturn(null);
permission.filter(containerRequestContext);
Response r = //Need the code. How to get the Response that i have set on permission class when id=null so that i can fetch the errorCode from that.
//With that erroCode i can write my test methods.
}
}
What you need is an ArgumentCaptor:
ArgumentCaptor<Response> argumentCaptor = ArgumentCaptor.forClass(Response.class);
verify(containerRequestContext).abortWith( argumentCaptor.capture() );
This checks if the method abortWith has been called exactly once (once being the default for verify) and stores the argument it has been called with in the ArgumentCaptor from which you can get it via...
Response response = argumentCaptor.getValue();
For further details see the JavaDoc.
Of course, there are other ways (for example, you could use an Answer) but they are not as easy.

Mockito session set Attribute null pointer exception

I am trying to set the session for testing, but i am getting NullPointerException. I have tried a couple of of ways, but could not succeed.
class Test {
public void testOne() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
session.setAttribute("test", someValue()); //session value is null
}
}
//This is my Unit Test which have one method giving exception.Why the session is giving null value....
Class TestUnitTest {
private TestUnit testUnit;
private ExternalContext externalContext;
private HttpServletRequest request;
private HttpSession httpSession;
#Before
public void init() {
testUnit = new TestUnit();
externalContext = Mockito.mock(ExternalContext.class);
Mockito.when(FacesContext.getCurrentInstance().getExternalContext()).thenReturn(externalContext);
request = Mockito.mock(HttpServletRequest.class);
Mockito.when(FacesContext.getCurrentInstance().getExternalContext().getRequest()).thenReturn(request);
httpSession = Mockito.mock(HttpSession.class);
Mockito.when((request.getSession())).thenReturn(httpSession);
//I am getting null pointer exception while implementing in this way
#Test
public void testvalueTest() {
testUnit.testOne(); //Null pointer exception
verify(httpSession).setAttribute("test", someValue());
}
//I am getting Wanted not Invoked while implementing in this way Wanted not Invoked
#Test
public void testvalueTest() {
verify(httpSession).setAttribute("test", someValue()); //Wanted not invoked
testUnit.testOne();
}
}
What I am doing wrong - what is the right approach to set the session?
externalContext = Mockito.mock(ExternalContext.class);
Mockito.when(FacesContext.getCurrentInstance().getExternalContext()).thenReturn(externalContext);
request = Mockito.mock(HttpServletRequest.class);
Mockito.when(FacesContext.getCurrentInstance().getExternalContext().getRequest()).thenReturn(request);
Mockito works by overriding instance methods, and can't override static methods. Though PowerMock does allow static method mocking, you can usually refactor the calls to static methods into instance methods and then mock using Mockito or other test override techniques.

Inject data into session from JUnit test

I need to run a JUnit vs Spring MVC test case in which preconditions include that certain data is present in the HTTP Session. Most important is that I cannot wire a session-scoped bean: I must access httpServletContext.getSession().
Before showing code, let me explain. The controller I need to test assumes that a certain datum is stored in session, otherwise throws an exception. And that is the correct behaviour for now, because that controller is never invoked without a session and the session is always initialized with application data at login time. And obviously the controller is under security.
In my test, I just need to test whether this controller returns either a redirection or a 404 not found according to the request parameters.
I thought building my test case such as
#Autowired
private HttpServletRequest httpServletRequest;
#Autowired
private ModuleManager moduleManager;
#Autowired
private WebApplicationContext webApplicationContext;
private MenuItem rootMenu;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception
{
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
// No asserzioni
.build();
rootMenu = moduleManager.getRootMenu()
.clone();
httpServletRequest.getSession()
.setAttribute(MenuItem.SESSION_KEY, rootMenu);
assertNotNull(rootMenu.getDescendant(existingSelectedMenu));
assertNull(rootMenu.getDescendant(notExistingMenu));
}
#Test
public void testNavigate() throws Exception
{
mockMvc.perform(get("/common/navigate?target=" + existingSelectedMenu))
.andExpect(status().is3xxRedirection());
assertNotSelected(rootMenu, existingSelectedMenu);
mockMvc.perform(get("/common/navigate?target=" + notExistingMenu))
.andExpect(status().is4xxClientError());
}
Part of the code is truly self-explaining. Anyway I expect /common/navigate to use the value I stored in the session. Like this
#RequestMapping(value = "/common/navigate",
method = RequestMethod.GET)
public String navigate(#RequestParam("target") String target) throws NotFoundException
{
MenuItem rootMenu = (MenuItem) httpServletRequest.getSession()
.getAttribute(MenuItem.SESSION_KEY);
if (rootMenu == null)
throw new RuntimeException("Menu not found in session"); //Never happens
MenuItem menuItem = rootMenu.getAndSelect(target);
if (menuItem == null)
throw new NotFoundException(MenuItem.class, target); //Expected
return "redirect:" + menuItem.getUrl();
}
Now guess. What happens when I run my code?
RuntimeException is thrown in the line I commented as the menu object is not found in the session
Obviously the question is implicit now, but I will still write it: how do I inject data into the Session object so that controllers under test will have them available as precondition?
Found the solution by myself now.
The problem is that the session itself must be mocked too. Spring provides a MockHttpSession class that does the trick. It can be pre-populated with all pre-conditions, but must be passed to every MockMvc request so that the mock will wire the session to the (mocked) servlet context.
Following code initializes the session
mockHttpSession = new MockHttpSession(webApplicationContext.getServletContext());
mockHttpSession.setAttribute(MenuItem.SESSION_KEY, rootMenu);
Following performs the request with mocked session wired to it
mockMvc.perform(get("/common/navigate?target=" + existingSelectedMenu).session(mockHttpSession))
.andExpect(status().is3xxRedirection());

Categories