我正在尝试使用方法级spring安全性来测试一些控制器,我想模拟控制器中的存储库依赖项。基本上我想测试(a)方法是否强制执行安全性以及(b)在SpEL表达式中调用的其他bean是否正常工作。
我的问题是,当使用Mockito的@InjectMocks实例化控制器时,Spring安全代理不会应用于控制器,并且绕过了方法安全性。如果我使用@Autowired来允许Spring创建控制器,我的自定义方法级安全逻辑会被调用,但不会注入@Mock对象。
@RestController
@RequestMapping("/api/projects/{projectId}")
public class ProjectKeywordResource {
//I want to mock this repository
@Inject
private ProjectKeywordRepository projectKeywordRepository;
//Invokes another bean if user not assigned admin role.
@PreAuthorize("hasRole('ROLE_ADMIN')" + " or "
+ "@projectService.canEditProjectData(#projectId)")
@RequestMapping(value = "/projectKeywords", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
public ResponseEntity<ProjectKeyword> create(
@PathVariable String projectId,
@RequestBody ProjectKeyword projectKeyword)
throws URISyntaxException {
projectKeywordRepository.save(projectKeyword);
return ResponseEntity.created(
new URI("/api/" + projectId + "projectKeywords/"
+ projectKeyword.getId())).body(result);
}
}
我的测试用例在这里:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class ProjectKeywordResourceSecurityTest {
private static final String DEFAULT_PROJECT_ID = "1";
@Mock
private ProjectKeywordRepository projectKeywordRepository;
//@Inject - Adding the following annotation adds the necessary spring security proxies,
but then ProjectKeywordResource uses the real ProjectKeywordRepository not the mock one.
@InjectMocks
private ProjectKeywordResource projectKeywordResource;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test(expected = AccessDeniedException.class)
@WithMockUser
@Transactional
public void testCreateThrowsAccessDenied() throws Exception {
projectKeywordResource.create(DEFAULT_PROJECT_ID, createDefaultProjectKeyword());
}
@Test
@WithMockUser(username = "admin", roles={"ADMIN"})
@Transactional
public void testCreateAuthorizationSuceedsForAdminUser() throws Exception {
projectKeywordResource.create(DEFAULT_PROJECT_ID, createDefaultProjectKeyword());
}
}
是否有一些配置魔法允许我用必要的弹簧代理包装Mockito模拟控制器,或者在我的测试用例中强制在注入的bean上使用Mock?
答案 0 :(得分:1)
Bewusstsein发布的链接让我在正确的轨道上找到了jfcorugedo发布的可行答案。基本上我要做的就是在我的测试配置类中创建一个新bean,它嘲笑Repository类并使用@Primary注释对其进行注释。添加Spring配置文件注释允许默认情况下关闭这些bean,因此不会干扰其他测试。修订后的测试类是:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@ActiveProfiles({"useMockRepositories","default"})
public class ProjectKeywordResourceSecurityTest {
private static final String DEFAULT_PROJECT_ID = "1";
@Inject
private ProjectKeywordResource projectKeywordResource;
@Test(expected = AccessDeniedException.class)
@WithMockUser
public void testCreateThrowsAccessDenied() throws Exception {
projectKeywordResource.create(DEFAULT_PROJECT_ID, createDefaultProjectKeyword());
}
@Test
@WithMockUser(username = "admin", roles={"ADMIN"})
public void testCreateAuthorizationSuceedsForAdminUser() throws Exception {
projectKeywordResource.create(DEFAULT_PROJECT_ID, createDefaultProjectKeyword());
}
我的测试配置类具有以下内容:
@Configuration
public class TestConfiguration {
@Profile("useMockRepositories")
@Bean
@Primary
public ProjectKeywordRepository MockProjectKeywordRepository() {
return Mockito.mock(ProjectKeywordRepository.class);
}
}