首页 > 解决方案 > 如何在许多休息控制器中测试相同的授权逻辑

问题描述

所以我有很多休息控制器,我想写一些可重用的授权测试方法

@RestController //1
public class PolicyController {
    @PreAuthorize("@securityService.hasAccess(#policy)")
    @GetMapping("policy/{policy}/group")
    ResponseEntity subgrups(String policy) {
        // impl
    }

    @PreAuthorize("@securityService.hasAccess(#policy)")
    @GetMapping("policy/{policy}/participants")
    ResponseEntity participants(String policy) {
        // impl
    }
}
@RestController//2
public class GroupController {

    @PreAuthorize("@securityService.hasAccess(#policy)")
    @GetMapping("policy/{policy}/group/{group}"
    ResponseEntity subgroups(String policy, String group) {
        // impl
    }
}
@RestController //...n

当我们遵循良好的做法时,我们应该为每一行代码编写测试,所以我可能应该写那么多重复的测试,如控制器数量 * 方法数量,所以这将是大量这样的重复代码

@WebMvcTest(controllers = PolicyController.class)
public class PolicyControllerTest {

    //...mock all controller dependencies

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private PolicySecurity policyApi;

    @Autowired
    private SecurityService securityService;

    @Test
    public void whenSearchingForGroupAndHasAccessToPolicy() throws Exception {
        when(policyApi.isActive(any())).thenReturn(false);

        mockMvc.perform(get("/policies/{policy}/group", "123")
                .contentType("application/json"))
                .andExpect(status().isOk());
    }

    @Test
    public void whenSearchingForGroupAndHasntAccessToPolicy() throws Exception {
        when(policyApi.isActive(any())).thenReturn(true);

        mockMvc.perform(get("/policies/{policy}/group", "123")
                .contentType("application/json"))
                .andExpect(status().isForbidden());
    }

    @Test
    public void whenSearchingForParticipantsAndHasAccessToPolicy() throws Exception {
        when(policyApi.isActive(any())).thenReturn(false);

        mockMvc.perform(get("/policies/{policy}/participants", "123")
                .contentType("application/json"))
                .andExpect(status().isOk());
    }

    @Test
    public void whenSearchingForParticipantsAndHasntAccessToPolicy() throws Exception {
        when(policyApi.isActive(any())).thenReturn(true);

        mockMvc.perform(get("/policies/{policy}/participants", "123")
                .contentType("application/json"))
                .andExpect(status().isForbidden());
    }

}

这只是一个具有两种方法的控制器,想象一下 5 个控制器和 30 个端点将有多少代码,知道如何以更易于维护的方式编写它吗?

标签: springspring-bootjunitspring-securityjunit5

解决方案


很少有关于可以做什么的指示。您可以根据安全配置对 API 进行分组,然后维护该组的 API 列表。这样,您只需为每个授权配置调用一个 write one 方法,您将在其中迭代每个 API 并运行 mockMvc 执行 API 方法。

for(api in api_list) {
    mockMvc.perform(get(api, "123")
                .contentType("application/json"))
                .andExpect(status().isForbidden());
}

如果将来任何一个 API 的安全配置发生变化,那么整个组的测试用例都会失败。这种方法的唯一问题是随着时间的推移维护测试用例会很困难,因为每次更改授权时都需要不断更新 API 列表。

请注意,最好为每个 API 方法编写独立的测试用例,以便仅测试该单元。


推荐阅读