测试了Mockito模拟和确保方法级弹簧安全性

时间:2015-11-23 04:27:59

标签: unit-testing spring-security mockito

我正在尝试使用方法级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?

1 个答案:

答案 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);
    }
}