春のセキュリティと、テンプレート処理にタイムリーフを使用する単純なホーム (ルート) コントローラーを使用して、春のブートで単体テストを実行しようとしています。セキュリティ権限が正しく機能していること、および適切なデータがテンプレートから非表示または表示されていることを確認するために、いくつかの単体テストを作成しようとしています (これは thymeleaf スプリング セキュリティ統合を使用します)。アプリ自体は、実行すると正しく動作します。一連の統合テストで機能していることを確認したいだけです。ここですべてのコードを見つけることができますが、関連するスニペットも以下に含めます。
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: Error during execution of processor 'org.thymeleaf.extras.springsecurity3.dialect.processor.AuthorizeAttrProcessor' (home:33) at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext (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 が含まれている場合にのみ発生します。テストの 1 つを無効にして springSecurityFilter コード ( .addFilter(springSecurityFilter, "/*")
) を削除すると、そのエラーは発生しなくなります。何かが WebApplicationContext を台無しにしているか、セキュリティを何らかの障害状態のままにしている可能性があると思われますが、何をリセットまたは変更する必要があるかわかりません。
したがって、2 番目のテストを実行して springSecurityFilter を削除すると、最初のテストは失敗しますが (特にこれはassertTrue(content.contains("Form Login endpoint"))
)、エラーは発生しなくなります。生成された HTML を見ると、sec:authorize
属性を使用するタグのコンテンツがまったく表示されません。
だから私は周りを検索し、追加する必要があるという提案を見つけましたspringSecurityFilter
(上記のコードサンプルで実行しました)が、それを行うとすぐに失敗します(要点にさえ達しません)それなしでは失敗します)。その例外の原因とその修正方法に関する提案はありますか?