You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用中Post与Put方法测试问题排查求助

解决Post和Put方法的测试问题

让我们逐个分析你遇到的问题,一步步排查解决:

Post方法错误:java.lang.IllegalArgumentException: 'url' is required

这个错误主要源于两个关键问题:

1. 错误Mock了MockMvc对象

你的Post测试代码里尝试mock mockMvc.perform(),这是完全错误的用法——MockMvc是我们发起测试请求的工具,根本不需要(也不应该)去mock它。我们要mock的是EmployeeRepository这类依赖组件的方法,比如save(),来模拟数据库操作。

2. Post请求缺少必要的请求体

控制器的newEmployee方法标注了@RequestBody Employee newEmployee,但测试时你没有传入任何请求体,Spring无法解析请求,这也会触发错误。

修正后的Post测试代码如下:

@Test
public void postEmployeeStatusIsOk() throws Exception {
    // 准备测试用的Employee对象
    Employee testEmployee = getTestEmployee();
    // mock repository的save方法,返回测试对象
    given(this.employeeRepository.save(any(Employee.class))).willReturn(testEmployee);
    
    // 发起Post请求,传入JSON格式的请求体
    mockMvc.perform(MockMvcRequestBuilders.post("/employees")
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(testEmployee))
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().is2xxSuccessful());
}

另外检查你的控制器Post方法:看起来你把ResponseEntity的构建代码注释掉了,这会导致方法无法正确返回响应(甚至可能编译失败)。请取消注释这部分代码:

@PostMapping("/employees")
ResponseEntity<?> newEmployee(@RequestBody Employee newEmployee) {
    EntityModel<Employee> entityModel = assembler.toModel(repository.save(newEmployee));
    return ResponseEntity
            .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri())
            .body(entityModel);
}

这个空指针异常的根源很清晰:

1. 控制器Put方法的核心逻辑被注释

你在replaceEmployee方法里注释掉了repository.findById(id)之后的.map()和.orElseGet()逻辑,导致updatedEmployee变量为null。当调用assembler.toModel(updatedEmployee)时,传入null会返回null的EntityModel,后续调用getRequiredLink()自然会触发NPE。

首先恢复控制器Put方法的核心逻辑:

@PutMapping("/employees/{id}")
ResponseEntity<?> replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {
    Employee updatedEmployee = repository.findById(id)
            .map(employee -> {
                employee.setName(newEmployee.getName());
                employee.setRole(newEmployee.getRole());
                return repository.save(employee);
            })
            .orElseGet(() -> {
                newEmployee.setId(id);
                return repository.save(newEmployee);
            });
    EntityModel<Employee> entityModel = assembler.toModel(updatedEmployee);
    return ResponseEntity
            .created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri())
            .body(entityModel);
}

2. 测试代码未Mock Repository的查询方法

你的Put测试中没有mockrepository.findById(1L)的返回值,导致它返回空的Optional,即使恢复了控制器逻辑,你也需要在测试中mock这个方法来返回预期的Employee对象,确保流程能正常执行。

修正后的Put测试代码:

@Test
public void putEmployeeStatusIsOk() throws Exception {
    var employee = getTestEmployee();
    employee.setId(1L);
    // mock repository.findById返回存在的Employee
    given(this.employeeRepository.findById(1L)).willReturn(Optional.of(employee));
    // mock save方法返回更新后的对象
    given(this.employeeRepository.save(any(Employee.class))).willReturn(employee);
    
    mockMvc.perform(MockMvcRequestBuilders.put("/employees/{id}", 1L)
            .contentType(MediaType.APPLICATION_JSON)
            .content(objectMapper.writeValueAsString(employee))
            .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().is2xxSuccessful());
}

额外提示

  • 确保你的getTestEmployee()方法返回的是一个完整、合法的Employee对象(包含name、role等必要字段)。
  • 测试HATEOAS相关的控制器时,也可以验证返回的响应中是否包含预期的链接,让测试更完整。

内容的提问来源于stack exchange,提问作者Daniel Kozak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 19:22:47