Spring Boot+JUnit测试Rest接口时参数名称异常问题
解决Spring MVC测试中参数名称无法获取的报错问题
嘿,我来帮你搞定这个头疼的测试报错!你遇到的IllegalArgumentException: Name for argument type [long] not available错误,主要是两个地方出了问题,咱们一步步来解决:
问题根源拆解
- 编译时丢失参数名:Spring MVC要绑定
@PathVariable这类注解,得明确知道参数的名称(比如你方法里的id),但默认Java编译会把参数名丢弃(尤其是Java 8以前的版本),导致Spring找不到参数名,直接抛出错误。 - 测试类Mock配置错误:你用
@MockBean注解了UserResourceController本身,这相当于把Spring自动创建的真实控制器替换成了一个空的Mock对象——不仅控制器的核心逻辑跑不起来,还会进一步加剧参数绑定的异常。
具体解决步骤
1. 让编译器保留参数名称
不管你用Maven还是Gradle,都要给编译器添加参数,确保它把方法参数名写入class文件:
- Maven(修改
pom.xml):
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <!-- 替换为你实际使用的Java版本 --> <target>1.8</target> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
- Gradle(修改
build.gradle):
compileJava { options.compilerArgs << "-parameters" }
添加这个参数后,Spring就能正确识别@PathVariable long id里的id参数了。
2. 修正测试类的Mock配置
@WebMvcTest(UserResourceController.class)注解已经帮你加载了控制器相关的Spring MVC环境,不需要Mock控制器本身。你应该Mock的是控制器依赖的组件(比如checkAccess方法调用的服务)。
修改后的测试类示例:
@RunWith(SpringRunner.class) @WebMvcTest(UserResourceController.class) public class UserResourceControllerTests { @Autowired private MockMvc mvc; // Mock控制器依赖的服务,比如假设checkAccess是UserAccessService中的方法 @MockBean private UserAccessService userAccessService; @Test public void getUser() throws Exception { // 先Mock依赖方法的返回值,模拟授权通过的场景 User mockUser = new User(); mockUser.setId(1L); when(userAccessService.checkAccess(any(HttpServletRequest.class), eq(1L))).thenReturn(mockUser); // 执行请求并验证结果 mvc.perform(get("/api/users/1") .with(user("pere.peris@gmail.com").password("password")) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1L)); // 可添加更多断言验证返回的用户信息 } }
这样修改后,Spring会使用真实的控制器实例,同时Mock它的依赖,测试就能正常执行了。
3. 小优化:移除不必要的注解配置
你的控制器方法中consumes = "application/json"是多余的——GET请求通常不会携带请求体,去掉它能避免一些不必要的参数解析问题:
@GetMapping(path = "/api/users/{id}", produces = "application/json") public ResponseEntity<User> getUser(HttpServletRequest request, @PathVariable long id) { User user = checkAccess(request, id); return ResponseEntity.ok(user); }
内容的提问来源于stack exchange,提问作者en Peris
相关产品推荐
相关产品推荐

