Issue
I tried to test my login servlet using mockito, but it return the error:
java.lang.NullPointerException: Cannot invoke "java.io.PrintWriter.println(String)" because "out" is null. at control.LoginPatient.doPost(LoginPatient.java:55) at control.LoginPatientTest.testDoPostSuccessfull(LoginPatientTest.java:64)
Here the code of my Login servlet:
package control;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import model.ProfileManager;
import model.Bean.UserBean;
/**
* Servlet implementation class LoginPatient
*/
@WebServlet("/LoginPatient")
public class LoginPatient extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginPatient() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fiscal_code=request.getParameter("fiscal_code");
String user_password= request.getParameter("user_password");
PrintWriter out = response.getWriter();
ProfileManager pM=new ProfileManager();
UserBean patient= pM.ReturnPatientByKey(fiscal_code, user_password);
if(patient != null) {
HttpSession session= request.getSession();
session.setAttribute( "user" , patient);
session.setMaxInactiveInterval(-1);
out.println("1");
}
else {
out.println("0");
}
}
}
and here my test case:
class LoginPatientTest {
private LoginPatient loginPatient;
private HttpServletRequest mockedRequest;
private HttpServletResponse mockedResponse;
private ServletContext mockedServletContext;
private HttpSession mockedSession;
private PatientBean patient;
private ProfileManager pm;
private PrintWriter mockedOut;
/**
* @throws java.lang.Exception
*/
@BeforeEach
void setUp() throws Exception {
loginPatient = new LoginPatient();
mockedRequest = Mockito.mock(HttpServletRequest.class);
mockedResponse = Mockito.mock(HttpServletResponse.class);
mockedSession = Mockito.mock(HttpSession.class);
mockedServletContext = Mockito.mock(ServletContext.class);
mockedOut = Mockito.mock(PrintWriter.class);
patient = Mockito.mock(PatientBean.class);
pm = Mockito.mock(ProfileManager.class);
}
/**
* @throws java.lang.Exception
*/
@AfterEach
void tearDown() throws Exception {
}
/**
* Test method for {@link control.LoginPatient#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}.
* @throws javax.servlet.ServletException
* @throws java.io.IOException
*/
@Test
final void testDoPostSuccessful() throws ServletException, IOException{
Mockito.doReturn(mockedServletContext).when(mockedRequest).getServletContext();
Mockito.when(mockedRequest.getParameter("fiscal_code")).thenReturn("fiscalCode");
Mockito.when(mockedRequest.getParameter("user_password")).thenReturn("password");
Mockito.when(mockedRequest.getSession()).thenReturn(mockedSession);
Mockito.when(pm.ReturnPatientByKey("fiscalCode", "password"));
Mockito.when(mockedResponse.getWriter()).thenReturn(mockedOut);
loginPatient.doPost(mockedRequest, mockedResponse);
Mockito.verify(mockedOut).println("1");
Mockito.verify(mockedSession).setAttribute(Mockito.eq("user"), patient);
}
}
I don't use Spring
Update: Now it gives me another error:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 2 matchers expected, 1 recorded: -> at control.LoginPatientTest.testDoPostSuccessful(LoginPatientTest.java:75) This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher")); For more info see javadoc for Matchers class. at control.LoginPatientTest.testDoPostSuccessful(LoginPatientTest.java:75) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:564) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:205) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:201) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248) at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211) at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:141) at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Solution
Issue 1:
In the mock setup change mockedOut variable to mockedOut = Mockito.mock(PrintWriter.class);
Issue 2:
You mocked out mockedOut
variable after you fires the business logic.
You should change the order. Mock everything before the business logic is invoked.
//Given
Mockito.doReturn(mockedServletContext).when(mockedRequest).getServletContext();
Mockito.when(mockedRequest.getParameter("fiscal_code")).thenReturn("fiscalCode");
Mockito.when(mockedRequest.getParameter("user_password")).thenReturn("password");
Mockito.when(mockedRequest.getSession()).thenReturn(mockedSession);
Mockito.when(pm.ReturnPatientByKey("fiscalCode", "password"));
Mockito.when(mockedResponse.getWriter()).thenReturn(mockedOut);
//When
loginPatient.doPost(mockedRequest, mockedResponse);
//Then
Mockito.verify(mockedOut).println("1");
Mockito.verify(mockedSession).setAttribute(Mockito.eq("user"), patient);
Answered By - tomeszmh