@MockBean 不适用于带有 JUnit 5 和 Spring Boot 2 的 @WebMvcTest?
Posted
技术标签:
【中文标题】@MockBean 不适用于带有 JUnit 5 和 Spring Boot 2 的 @WebMvcTest?【英文标题】:@MockBean doesn't work for @WebMvcTest with JUnit 5 and Sping Boot 2? 【发布时间】:2019-09-07 16:50:00 【问题描述】:我在 *** 上研究了类似的问题,但在我的案例中找不到根本原因。
上下文:
我在SpringBoot 2
中有@RestController
,依赖于BookSearcherService
。我想模拟 BookSearcherService
以便对控制器进行单元测试。
错误:
org.springframework.web.util.NestedServletException: 请求 处理失败;嵌套异常是 java.lang.NullPointerException 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1013) 在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:634) 在 org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) 在 org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:71) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:741) 在 org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:166) 在 org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133) 在 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133) 在 org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133) 在 org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133) 在 org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:182) 在 com.search.book.Booksearcher.controller.BookSearcherControllerMockMvcTest.canListAll(BookSearcherControllerMockMvcTest.java:54) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532) 在 org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:171) 在 org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:108) 在 org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74) 在 java.util.ArrayList.forEach(ArrayList.java:1257) 在 org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112) 在 org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74) 在 java.util.ArrayList.forEach(ArrayList.java:1257) 在 org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112) 在 org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98) 在 org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74) 在 org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) 在 org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220) 在 org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188) 在 org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202) 在 org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181) 在 org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128) 在 org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209) 引起:java.lang.NullPointerException at com.search.book.Booksearcher.controller.BookSearcherController.listAll(BookSearcherController.java:31) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) 在 org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) 在 org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) 在 org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ... 59 更多
代码:
BookSearcherController.java
:
@RestController
@RequestMapping("/book")
@RequiredArgsConstructor
public class BookSearcherController
private BookSearcherService bookSearcherService;
@GetMapping(path = "/list", produces = "application/json" )
@ResponseBody
public List<BookDto> listAll()
return bookSearcherService.listAll();
BookSearcherService.java
:
@Service
public class BookSearcherService
private BookSearcherCrudService bookSearcherCrudService;
@Autowired
void setBookSearcherRepository(BookSearcherCrudService bookSearcherCrudService)
this.bookSearcherCrudService = bookSearcherCrudService;
private BookSearcherRepository bookSearcherRepository;
@Autowired
void setBookSearcherRepository(BookSearcherRepository bookSearcherRepository)
this.bookSearcherRepository = bookSearcherRepository;
public List<BookDto> listAll()
List<Book> books = bookSearcherRepository.findAll();
return books.stream()
.map(bookSearcherCrudService::toDto)
.collect(Collectors.toList());
BookSearcherControllerMockMvcTest.java
:
@WebMvcTest(controllers = BookSearcherController.class)
public class BookSearcherControllerMockMvcTest
@Autowired
private MockMvc mockMvc;
@MockBean
private BookSearcherService bookSearcherService;
@Autowired
private ObjectMapper objectMapper;
@Test
public void canListAll() throws Exception
assertThat(bookSearcherService).isNotNull();
assertThat(mockMvc).isNotNull();
List<BookDto> books = asList(new BookDto("Title 1"), new BookDto("Title 2"), new BookDto("Title 3"));
given(bookSearcherService.listAll()).willReturn(books);
ResultActions perform = mockMvc.perform(get("/book/list"));
POM.XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.search.book</groupId>
<artifactId>book-searcher</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>book-searcher</name>
<description>Project for books search</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
问题:
如上所述的问题是BookSearcherService
在对mockMvc
执行调用时具有null
。这意味着要么@MockBean
不起作用,要么我犯了一个几个小时都无法发现的错误。我正在使用Java8
。
【问题讨论】:
问题可能是bookSearcherService
没有被注入BookSearchController
,因为它使用了@RequiredArgsConstructor
,它没有添加@Autowired
注解。
@ArhoHuttunen 有帮助。
很好,我会改为回答。
【参考方案1】:
问题在于bookSearcherService
没有被注入到BookSearchController
中,因为它使用了@RequiredArgsConstructor
,在这种情况下不会创建正确的构造函数。
@RequiredArgsConstructor
文档指出,将使用未初始化的 final
或 @NonNull
字段的参数创建构造函数。但是,bookSearcherService
两者都不是,因此它没有作为构造函数参数添加。
因此,尽管 mock 本身不为 null,但它永远不会注入到测试的控制器中。
【讨论】:
我确信@RequiredArgsConstructor
可以完成@Autowired
的工作。谢谢。
它应该作为一个单一的构造函数,从 spring 4.2 或 4.3 iirc 开始尝试,有点奇怪
其实你是对的,但是@RequiredArgsConstructor
在这里工作正常吗,因为bookSearcherService
既不是final
也不是@NonNull
?
我已更改答案以反映这一点。以上是关于@MockBean 不适用于带有 JUnit 5 和 Spring Boot 2 的 @WebMvcTest?的主要内容,如果未能解决你的问题,请参考以下文章
Junit 测试不适用于 Drools 5.4.0.Final 和 JDK 8
事务不适用于 Spring 3.1 – H2 – junit 4 – hibernate 3.2
ContextConfiguration不适用于测试平台的JUnit4类