Spring Controller测试报错:无法解析crossOrigin占位符问题排查
你遇到的问题核心在于测试用例的MockMvc构建方式:你用了StandaloneMockMvcBuilder(也就是standaloneSetup())来初始化Controller,这种方式是独立创建Controller实例,不会加载完整的Spring上下文,自然也不会读取application.properties里的配置项,所以Spring没法解析@CrossOrigin(origins = "${crossOrigin}")中的占位符,导致报错。
而实际运行服务时,Spring会启动完整的上下文,自动加载配置文件,所以${crossOrigin}能正常解析,服务也能被正常访问。
下面给你三种可行的解决办法,你可以根据自己的需求选择:
方法1:改用@WebMvcTest注解(推荐)
这种方式会加载Spring MVC相关的上下文,自动读取配置文件,更贴近真实运行环境,是Spring官方推荐的Controller测试方式。
修改你的测试类:
@RunWith(SpringRunner.class) @WebMvcTest(AccountController.class) // 加载AccountController相关的MVC上下文 public class TestAccountController { @Autowired private MockMvc mockMvc; @MockBean // 用@MockBean替代@Mock+@InjectMocks,因为WebMvcTest会管理Bean private AccountService accountService; @Test public void findLocationTest() throws Exception { Account account = new Account(); account.setsLocation("US"); account.setsLocation("pune"); // 这里注意你重复设置了sLocation,可能是笔误? List<Account> accountObj = new ArrayList<>(); accountObj.add(account); Mockito.when(accountService.findLocation()).thenReturn(accountObj); mockMvc.perform(get("/api.spacestudy.com/spacestudy/rockefeller/admin/account/loadAcctLocationList")) .andExpect(status().isOk()) .andExpect(jsonPath("$[0].sLocation", is("pune"))); } }
注意:这里用@MockBean代替了原来的@Mock和@InjectMocks,因为@WebMvcTest会创建Spring上下文,需要用@MockBean来替换上下文中的真实AccountService。
方法2:在standaloneSetup中手动添加配置源
如果你坚持要用standaloneSetup,可以手动给它添加PropertySource,提供crossOrigin的值:
修改测试类的setup方法:
@Before public void setup() { // 创建一个PropertySource,提供crossOrigin的值 MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addFirst(new MapPropertySource("testProps", Collections.singletonMap("crossOrigin", "http://localhost:4200"))); mockMvc = MockMvcBuilders.standaloneSetup(accountController) .setPlaceholderValues(propertySources) // 设置占位符解析的源 .build(); }
这样MockMvc就能解析${crossOrigin}占位符了。
方法3:给占位符设置默认值
在@CrossOrigin注解里给占位符加默认值,这样即使测试环境没加载配置,也会用默认值:
修改AccountController的注解:
@CrossOrigin(origins = "${crossOrigin:http://localhost:4200}")
这种方式最简单,不需要修改测试代码,适合占位符有合理默认值的场景。
推荐用方法1,因为它更符合Spring测试的最佳实践,能覆盖更多MVC相关的逻辑;如果只是临时解决,方法3最快捷;方法2适合需要完全控制测试环境的场景。
内容的提问来源于stack exchange,提问作者SpringUser

