@MockBean不适用于带有JUnit 5和Sping Boot 2的@WebMvcTest吗?

时间:2019-04-17 12:28:02

标签: java maven unit-testing spring-boot junit5

我在StackOverflow上研究了类似的问题,但无法找到根本原因。

上下文:

我在@RestController中有SpringBoot 2,并且依赖于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(本机方法)处   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   com.search.book.Booksearcher.controller.BookSearcherController.listAll(BookSearcherController.java:31)     在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处   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>

问题:

如上所述,问题是BookSearcherServicemockMvc上执行呼叫时有null。这意味着@MockBean不起作用,或者我犯了一个无法在几个小时内发现的错误。我正在使用Java8

1 个答案:

答案 0 :(得分:2)

问题在于bookSearcherService不会被注入BookSearchController,因为它使用的是@RequiredArgsConstructor,在这种情况下不会创建正确的构造函数。

@RequiredArgsConstructor文档指出,将使用未初始化的final@NonNull字段的参数创建构造函数。但是,bookSearcherService都不是,因此不会作为构造函数参数添加。

因此,尽管模拟本身不为null,但它永远不会注入到经过测试的控制器中。