작성
·
823
3
test의 경우 EventRepository에 save를 하고 난 값이 리턴되지 않기 때문에 Mockito를 이용해서 객체를 그대로 리턴해주는 식으로 이해했습니다. 그런데 이 부분에서 똑같이 NPE가 발생하길래 왜 그런가 봤더니 Event 엔티티의 @EqualsAndHashCode 사용 유무 문제였습니다.
여기서 의문이 드는게 @EqualsAndHashCode가 Mockito의 리턴이랑 무슨 관계인지 이해가 안갑니다. 단순히 Test에서 만든 Event 객체를 다시 리턴시키는데 왜 @EqualsAndHashCode가 영향을 미치는 건가요??
답변 14
4
오 생각보다 복잡한 이슈였네요.
Mockito.when(eventRepository.save(event)).thenReturn(event);
여기 보시면 save에 넘겨주는 event가 있고 그 객체가 넘어오면 event를 리턴하라고 스터빙을 한건데요.
@EAH가 없으면 여기서 목킹하면서 save에 넘겨주는 event 객체랑 컨트롤러 안에서 save 호출할 때 넘겨주는 event 객체랑..
Event newEvent = this.eventRepository.save(event);
서로 다르다고 생각해서 stubbing을 제대로 적용 안하고 (즉 리턴하라고 했던 event)를 넘겨주지 않고.. 그냥 null이 리턴 됩니다. 그래서 newEvent가 null이 되요.
URI createdURi = linkTo(EventController.class).slash(newEvent.getId()).toUri();
그 상태에서 바로 아래 줄인 저기서 getId를 null에다가 호출하니까 NPE가 발생한겁니다.
@EAH를 사용하시거나, equals랑 hashCode를 직접 구현해서 목킹할 때 넘겨준 객체랑 실제 객체가 같은지 확인 될 수 있게끔 해주시거나..
아니면 테스트 코드를 이렇게 바꿔주시면 아무런 Event 타입의 객체만 받아도 항상 event 객체를 리턴하도록 했기 때문에 @EAH가 없어도 테스트는 잘 동작할 겁니다.
Mockito.when(eventRepository.save(any(Event.class))).thenReturn(event);
0
0
와 한번에 이해한 것 같습니다.
정리하자면 Mockito에서 when()이 일반적인 이벤트리스너 함수처럼 호출되는 메소드만 같다고 작동하는 것이 아니라 실제로 매개변수에 들어가는 객체까지 같아야 작동하는 것이군요..! 그렇기 때문에 객체를 비교하는 equals()와 hashCode()가 필요한거구요!
바쁘신데 명쾌하고 빠른 답변 정말 감사합니다!
0
0
0
0
넵. 확인해주시기 쉽게 최대한 같은 코드로 올렸습니다.
github : https://github.com/tj3828/RestAPI-NPE
Error :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1013)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:166)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:182)
at com.example.npe.events.EventControllerTest.createBoard(EventControllerTest.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.NullPointerException
at com.example.npe.events.EventController.createEvent(EventController.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
... 48 more
0
0
0
0
0
0
5분 30초 부근입니다.
test가 아닌 실제 서버에서는 상관없는데,
test의 경우에만 Event에 @EqualsAndHashCode가 없으면 여전히 NPE가 발생합니다.
이 상황을 보면, Mokito의 thenReturn 메소드가 @EqualsAndHashCode와 연관이 있는 것 같다고 생각하는데 그 이유를 모르겠어서 질문드렸습니다.
0