【问题标题】:NPE returned by a mocked function spring boot由模拟函数 spring boot 返回的 NPE
【发布时间】:2020-02-19 15:41:02
【问题描述】:

我是测试新手,我正在尝试使用 JUnit 和 Spring Boot 学习单元测试,但出现了异常。 正如你所看到的,我在 TopicSevices 中模拟了我需要的函数的行为,但我仍然得到这个 NPE,我还尝试添加

MockitoAnnotations.initMocks(this);

但是没有用。

控制器代码

package com.example.test.controller;

import java.util.List;

import javax.validation.Valid;

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.test.Services.ExerciceServices;
import com.example.test.Services.TopicService;
import com.example.test.model.Difficulty;
import com.example.test.model.Exercice;
import com.example.test.model.Status;
import com.example.test.model.dto.ExerciceDTO;

@CrossOrigin("*")
@RestController
public class ExerciceController {

    private final ExerciceServices exerciceServices;
    private final TopicService topicServices;

    public ExerciceController(ExerciceServices exerciceServices, TopicService topicServices) {

        this.exerciceServices = exerciceServices;
        this.topicServices = topicServices;
    }

    @GetMapping("/exercices")
    public List<Exercice> allExercices() {
        return exerciceServices.getAllExecices();
    }

    @PostMapping("/exercices")
    public Exercice createExercice(@Valid @RequestBody ExerciceDTO dto) {

        Exercice exercice = createExcerciceFromDto(dto);

        return exerciceServices.CreateeExercice(exercice);
    }

    public Exercice createExcerciceFromDto(ExerciceDTO dto) {

        Exercice exercice = new Exercice();

        exercice.setDifficulty(dto.getDifficulty());
        exercice.setImg(dto.getImg());
        exercice.setStatus(dto.getStatus());
        exercice.setTitle(dto.getTitle());

        for (Long id : dto.getListToppicId()) {
            try {
                System.out.println(topicServices.getTopicById(id));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return exercice;
    }

    @GetMapping("/exercices/filter")
    public List<Exercice> getExeerciceByDifficulty(@RequestParam(required = false) Long id,
            @RequestParam Difficulty difficulty, @RequestParam Status status) {

        return exerciceServices.exercicesFilterTopic(id, difficulty, status);

    }

}

测试代码

package com.example.test.controller;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

import com.example.test.Services.ExerciceServices;
import com.example.test.Services.TopicService;
import com.example.test.model.Difficulty;
import com.example.test.model.Exercice;
import com.example.test.model.Status;
import com.example.test.model.Topic;
import com.example.test.model.dto.ExerciceDTO;

@RunWith(MockitoJUnitRunner.class)
@WebMvcTest

class ExerciceControllerTest {


    @MockBean
    private ExerciceServices exerciceServices;

    @MockBean
    private TopicService topicServices;

    @InjectMocks
    private ExerciceController exerciceController;

    ExerciceDTO dto = new ExerciceDTO();
    Exercice e = new Exercice();
    Topic t = new Topic();

    @BeforeEach
    public void setUp() throws Exception {
        Mockito.when(exerciceServices.getAllExecices()).thenReturn(Arrays.asList(e));
    }

    @Test
    public void givenDTOCreateTheExercice() {
        dto.setDifficulty(Difficulty.EASY);
        dto.setImg("link");
        dto.setStatus(Status.FINISHED);
        dto.setTitle("title");
        dto.setListToppicId(new HashSet<>(Arrays.asList(6L)));

        e.setDifficulty(Difficulty.EASY);
        e.setImg("link");
        e.setStatus(Status.FINISHED);
        e.setTitle("title");

        t.setId(6L);
        t.setTitle("romayssae");

        e.setTopics(new HashSet<>(Arrays.asList(t)));
        Optional<Topic> topic = Optional.of(t);

        Mockito.when(topicServices.getTopicById(6L)).thenReturn(topic);

        System.out.println(topicServices.getTopicById(6L));

        assertEquals(e, exerciceController.createExcerciceFromDto(dto));
    }


}

例外

java.lang.NullPointerException
    at com.example.test.controller.ExerciceController.createExcerciceFromDto(ExerciceController.java:58)
    at com.example.test.controller.ExerciceControllerTest.givenDTOCreateTheExercice(ExcerciceControllerTest.java:77)
    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.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
    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:104)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
    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:202)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    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:1540)
    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:1540)
    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:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

【问题讨论】:

标签: java spring spring-boot unit-testing junit


【解决方案1】:

尝试使用@Mock 而不是@MockBean。应该没问题的

【讨论】:

  • 我试过了,但它给了我这个异常 java.lang.IllegalStateException: Failed to load ApplicationContext
【解决方案2】:

我试过了,它对我有用,但是我不明白为什么。

简而言之,我按照@arbuzov 的建议更改了@Mock 而不是@MockBean。然后我得到了这个异常:

java.lang.IllegalStateException: 无法加载 ApplicationContext

为了解决这个问题,我添加了这两个注释 @SpringBootTest@AutoConfigureMockMvc。然后我尝试使用 MockMvc 测试另一种方法,再次模拟的行为被忽略了,所以我改回 @MockBean 工作。

如果有人有的话,我很乐意收到任何 cmets 及其工作原理的解释。

package com.example.test.controller;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import com.example.test.Services.ExerciceServices;
import com.example.test.Services.TopicService;
import com.example.test.model.Difficulty;
import com.example.test.model.Exercice;
import com.example.test.model.Status;
import com.example.test.model.Topic;
import com.example.test.model.dto.ExerciceDTO;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc

class ExerciceControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private ExerciceServices exerciceServices;

    @Mock
    private TopicService topicServices;

    @InjectMocks
    private ExerciceController exerciceController;

    ExerciceDTO dto = new ExerciceDTO();
    Exercice e = new Exercice();
    Topic t = new Topic();

    @BeforeEach
    public void setUp() throws Exception {

    }

    @Test
    public void givenDTOCreateTheExercice() {

        assertEquals(e, exerciceController.createExcerciceFromDto(dto));
    }

    @Test
    public void eznekfnzre() throws Exception {
        dto.setDifficulty(Difficulty.EASY);
        dto.setImg("link");
        dto.setStatus(Status.FINISHED);
        dto.setTitle("title");
        dto.setListToppicId(new HashSet<>(Arrays.asList(6L)));

        e.setDifficulty(Difficulty.EASY);
        e.setImg("link");
        e.setStatus(Status.FINISHED);
        e.setTitle("title");

        t.setId(6L);
        t.setTitle("romayssae");

        e.setTopics(new HashSet<>(Arrays.asList(t)));
        Optional<Topic> topic = Optional.of(t);

        Mockito.when(topicServices.getTopicById(6L)).thenReturn(topic);
        Mockito.when(exerciceServices.getAllExecices()).thenReturn(Arrays.asList(e));
        mockMvc.perform(get("/exercices/").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
                .andExpect(jsonPath("$[0].title", is(e.getTitle())));
    }

}

【讨论】:

  • 你想在这里做什么?您的第一个测试使用了 Mockitos 运行程序,并且似乎只测试了您的 java 逻辑(尽管有一些非常混合的模拟注释)这个测试包括一个带有真正 mvc 测试的 spring 上下文(我不相信您实际使用您的 topicServices 模拟..您可能想要验证这一点。你可能正在使用一个“真正的”topicServices bean,当你的测试 conext 开始时,它会被 spring 拾取)(如果没有那个 mockitoRunner,你的 @InjectMocks 注释也可能不再在这里做任何事情
  • 我在上一条评论中由于长度限制而被截断。如果您能详细说明您想要测试的内容以及您希望如何测试它,我们可以帮助解决例外情况
  • 我想要在这里测试两个函数 createExerciceFromDto 和 allExercices 函数它们都在控制器中。首先我尝试了createExerciceFromDto cz,当我得到NPE时它只是java逻辑然后我使用了arbuzov建议的内容并得到了失败的加载异常,之后我添加了我之前提到的两个注释并且它起作用了,一旦我这样做了我试过了测试第二个功能,但它没有工作,所以我在我正在使用的服务上尝试了@MockBean,它再次工作。但我很困惑这整件事是如何运作的。
  • 您提到我的注释混淆了,因此我想要一个关于如何使我的代码更好的建议,并感谢您的帮助??
  • 当您找到答案时,找到您想要答案的新问题是很正常的。虽然将这些作为一个小问题添加到答案中可能是可以的,但答案实际上并不是为了发布新问题。如果可以的话,最好向他们提出一个新问题。
猜你喜欢
  • 1970-01-01
  • 2020-05-02
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多