尝试使用 JUnit、Mockito 测试 Spring MVC 控制器方法时出现 NullPointerException

NullPointerException while trying to test a Spring MVC controller method with JUnit, Mockito

我正在尝试对 Spring MVC 控制器方法进行单元测试,但我的单元测试一直失败。

我有一个 Spring MVC 控制器方法:

// MyController.java
@RequestMapping(value = "/end-point", method = RequestMethod.GET)
public ModelAndView getData(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    ModelAndView mv = new ModelAndView();
    DataManager dataManager = DataManager.getInstance();
    DataUser currentUser = (DataUser) request.getSession().getAttribute("currentUser");
    List<DataItem> dataList = dataManager.getDataForUser(currentUser.getId());
    mv.addObject("dataList", dataList);
    mv.setViewName("home-page");
    return mv;
}

我正在尝试使用 JUnit 测试此控制器方法。我的单元测试经验很少,正在努力学习。如果没有模拟库,这似乎几乎不可能或没有意义,而且我正在处理的项目已经将 Mockito 作为依赖项,因此我正在尝试使用它。我的测试 class 如下:

//MyControllerTest.java
public class MyControllerTest {
    @InjectMocks
    private MyController myController;

    @Mock
    HttpServletRequest request;

    @Mock
    HttpServletResponse response;

    @Mock
    ModelAndView mockModelAndView;

    @Mock
    DataManager mockDataManager;

    @Mock
    DataUser mockDataUser;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void getDataTest() throws Exception {
        //I guess I have to somehow mock mockDataUser here even more than @Mock???
        Mockito.when(request.getSession().getAttribute("currentUser")).thenReturn(mockVendorUser); // <-- this is where the null pointer exception is coming from
        Mockito.when(myController.getData(request, response)).thenReturn(mockModelAndView); 
        ModelAndView testing = profileControllerWH.getMySkus(request, response);
        assertEquals(1, 1);
    }
}

当我 运行 我的测试时,它失败了,我在控制台中得到一个 java.lang.NullPointerException 异常,用空指针异常注释指定上面的行。

我已经尝试查找如何使用 Mockito 模拟 classes,并且我一直看到 @Mock 注释,我已经将其作为 @Mock DataUser(以及其他 classes 我在我想我需要模拟的控制器方法中使用)。

我如何让它工作?似乎我必须用假数据创建一个全新的 DataUser 对象,但这似乎违背了模拟库的目的。如果我必须用假数据创建自己的对象,那么使用 Mockito 有什么意义呢?或者,我可能因为缺乏经验而误解了这一点。

请记住,默认情况下,unstubbed 方法 return 调用时 return 类型的默认值(数字为 0,对象为 null)。

你还没有存根 request.getSession() 所以它 return 是空的。

您需要:

  • 为会话提供模拟
  • request.getSession() 存根到 return 这个模拟
  • 存根session.getAttribute("currentUser")

最重要的是:

虽然在测试中调用控制器方法当然具有测试方法主体的价值,但如果将测试重新实现为 @WebMvcTest[,您将测试更多功能(如请求和响应序列化) =14=]