我正在尝试使用 spring security 和一个使用 thymeleaf 进行模板处理的简单家庭(根)控制器在 spring-boot 中运行单元测试。我正在尝试编写一些单元测试来验证我的安全权限是否正常工作,并且正确的数据是否从我的模板中隐藏或显示(它使用 thymeleaf spring 安全集成)。当我运行它时,应用程序本身可以正常工作。我只是想验证它是否正在使用一组集成测试。您可以在此处找到所有代码,但我还将在下面包含相关代码段:
https://github.com/azeckoski/lti_starter
控制器非常简单,除了渲染模板(在根 - 即“/”)之外什么也不做。
@Controller
public class HomeController extends BaseController {
@RequestMapping(method = RequestMethod.GET)
public String index(HttpServletRequest req, Principal principal, Model model) {
log.info("HOME: " + req);
model.addAttribute("name", "HOME");
return "home"; // name of the template
}
}
模板中有很多内容,但测试的相关位是:
<p>Hello Spring Boot User <span th:text="${username}"/>! (<span th:text="${name}"/>)</p>
<div sec:authorize="hasRole('ROLE_USER')">
This content is only shown to users (ROLE_USER).
</div>
<div sec:authorize="isAnonymous()"><!-- only show this when user is NOT logged in -->
<h2>Form Login endpoint</h2>
...
</div>
最后是测试:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class AppControllersTest extends BaseApplicationTest {
@Autowired
WebApplicationContext wac;
@Autowired
private FilterChainProxy springSecurityFilter;
private MockMvc mockMvc;
@Before
public void setup() {
// Process mock annotations
MockitoAnnotations.initMocks(this);
// Setup Spring test in webapp-mode (same config as spring-boot)
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.addFilter(springSecurityFilter, "/*")
.build();
}
@Test
public void testLoadRoot() throws Exception {
// Test basic home controller request
MvcResult result = this.mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
.andReturn();
String content = result.getResponse().getContentAsString();
assertNotNull(content);
assertTrue(content.contains("Hello Spring Boot"));
assertTrue(content.contains("Form Login endpoint"));
}
@Test
public void testLoadRootWithAuth() throws Exception {
Collection<GrantedAuthority> authorities = new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication authToken = new UsernamePasswordAuthenticationToken("azeckoski", "password", authorities);
SecurityContextHolder.getContext().setAuthentication(authToken);
// Test basic home controller request
MvcResult result = this.mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
.andReturn();
String content = result.getResponse().getContentAsString();
assertNotNull(content);
assertTrue(content.contains("Hello Spring Boot"));
assertTrue(content.contains("only shown to users (ROLE_USER)"));
}
}
我在上述两个测试中得到的错误是:
testLoadRoot(ltistarter.controllers.AppControllersTest) 已用时间:0.648 秒 <<< 错误!org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常是 org.thymeleaf.exceptions.TemplateProcessingException:在 org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext 处执行处理器“org.thymeleaf.extras.springsecurity3.dialect.processor.AuthorizeAttrProcessor”(home:33)时出错(WebApplicationContextUtils.java:84) 在 org.thymeleaf.extras.springsecurity3.auth.AuthUtils.getExpressionHandler(AuthUtils.java:260) 在 org.thymeleaf.extras.springsecurity3.auth.AuthUtils.authorizeUsingAccessExpression(AuthUtils.java:182) 在org.thymeleaf.extras.springsecurity3.dialect.processor.AuthorizeAttrProcessor。
但是,只有在启用两个测试并且包含 springSecurityFilter 时才会发生这种情况。如果我禁用其中一项测试并删除 springSecurityFilter 代码(.addFilter(springSecurityFilter, "/*")
),那么我将不再收到该错误。我怀疑某些东西可能会弄乱 WebApplicationContext 或使安全性内容处于某种故障状态,但我不确定我需要重置或更改什么。
因此,如果我取出第二个测试并删除 springSecurityFilter 那么我的第一个测试仍然会失败(特别是这个assertTrue(content.contains("Form Login endpoint"))
),但我不再收到任何错误。当我查看生成的 HTML 时,我没有看到任何使用该sec:authorize
属性的标签内容。
所以我四处搜索,发现一个我需要添加的建议springSecurityFilter
(我在上面的代码示例中已经完成了),但是,一旦我这样做了,我立即得到了失败(它甚至没有达到重点没有它就会失败)。关于导致该异常的原因以及如何解决它的任何建议?