org.springframework.web.util.NestedServletException : 单元测试中的 MockMVC 请求处理失败

Posted

技术标签:

【中文标题】org.springframework.web.util.NestedServletException : 单元测试中的 MockMVC 请求处理失败【英文标题】:org.springframework.web.util.NestedServletException : Request processing failed For MockMVC in unit test 【发布时间】:2021-01-26 11:42:46 【问题描述】:

当我尝试编写负单元测试用例以获取用户定义的异常 UnauthenticatedException 时,执行 mockmvc 代码后它向我抛出异常并且测试用例失败。

(org.springframework.web.util.NestedServletException: 请求处理失败;嵌套异常是 com.exception.UnauthenticatedException:无效的凭据!)*

@Test
public void loginUser_NotAuthorised() throws Exception 
    User user = new User();
    user.setUsername("user");
    user.setPassword("");
        when(loginService.loginUser(ArgumentMatchers.any(User.class)))
                .thenThrow(new UnauthenticatedException("Invalid Credentials!"));

         mockMvc.perform(post("/login").contentType(MediaType.APPLICATION_JSON)
                .content(mapper.writeValueAsString(user)).characterEncoding("utf-8").accept(MediaType.APPLICATION_JSON))            
                .andExpect(status().isUnauthorized()).andDo(print()).andReturn();

这是收到的异常

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.exception.UnauthenticatedException: Invalid Credentials!
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:183)
at com.tests.controller.LoginControllerTest.loginUser_NotAuthorised(LoginControllerTest.java:169)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
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:366)
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$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
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$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:43)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:82)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:73)
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)
Caused by: com.exception.UnauthenticatedException: Invalid Credentials!
at com.controller.LoginController.loginUser(LoginController.java:28)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
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:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
... 67 more

我也有疑问,可以为 Mockito 和 MockMVC 组合编写所有可能的单元测试用例方式,您是否也可以共享资源和示例项目?

具有所有导入的LoginTestController 类

 package com.tests.controller;

    import static org.hamcrest.Matchers.containsString;
    import static org.junit.Assert.assertEquals;
    import static org.mockito.Mockito.when;
    import static 
    org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static 
    org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
    import static 
    org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
    import static 
    org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
    import static 
    org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    import static 
    org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.ArgumentMatchers;
    import org.mockito.Matchers;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
    import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.http.MediaType;
    import org.springframework.mock.web.MockHttpServletResponse;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.MvcResult;
    import org.springframework.test.web.servlet.ResultActions;
    import org.springframework.test.web.servlet.ResultMatcher;
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
    
    import com.beans.User;
    import com.controller.LoginController;
    import com.service.impl.LoginServiceImpl;
    import com.exception.UnauthenticatedException;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    @RunWith(SpringRunner.class)
    @WebMvcTest(value = LoginController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
    @ContextConfiguration(classes =  LoginController.class )
    
    public class LoginControllerTest 

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    LoginServiceImpl loginService;

    @Autowired
    private ObjectMapper mapper;

    @Test
    public void loginUser_NotAuthorised() throws Exception 
        User user = new User();
        user.setUsername("user");
        user.setPassword("");
        when(loginService.loginUser(ArgumentMatchers.any(User.class)))
                .thenThrow(new UnauthenticatedException("Invalid Credentials!"));
        mockMvc.perform(post("/login").contentType(MediaType.APPLICATION_JSON)
                .content(mapper.writeValueAsString(user)).characterEncoding("utf-8").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isUnauthorized())
                .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Invalid Cr

    edentials!")).andDo(print())
                    .andReturn();
        
    
     

【问题讨论】:

【参考方案1】:

我认为您需要将期望更改为低于 1

mockMvc.perform(post("/login").contentType(MediaType.APPLICATION_JSON)
                .content(mapper.writeValueAsString(user)).characterEncoding("utf-8").accept(MediaType.APPLICATION_JSON))            
                .andExpect(status().isUnauthorized()).andExpect(
                MockMvcResultMatchers.jsonPath("$.message").value("Invalid Credentials!"));

【讨论】:

我试过这个接收相同的异常(org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常是 com.exception.UnauthenticatedException:无效凭据!) 你能用导入更新你的整个测试类吗?【参考方案2】:

我知道它很老的线程,

我也有同样的问题,这里的罪魁祸首是你的服务实现 Mock 对象

不是这个

  when(loginService.loginUser(ArgumentMatchers.any(User.class)))
            .thenThrow(new UnauthenticatedException("Invalid Credentials!"));

使用这个

  LoginServiceImpl loginService = Mockito.mock(LoginServiceImpl.class)
  Mockito.doThrow(new UnauthenticatedException("Invalid Credentials!"))
         .when(loginService)
         .loginUser(ArgumentMatchers.any(User.class))

如果您在上面看到,您应该模拟您的 impl 类,然后将该模拟对象传递给 when 并调用您的方法。

它对我有用。

【讨论】:

以上是关于org.springframework.web.util.NestedServletException : 单元测试中的 MockMVC 请求处理失败的主要内容,如果未能解决你的问题,请参考以下文章