可以使用 MockMvc 测试 Spring 受安全保护的控制器吗?

Testing Spring Security protected Controllers with MockMvc possible?

我想弄清楚,什么是测试我的 Spring 启动应用程序安全配置的最佳方法。我的目标是进行两次测试:

开始我的研究时,我找到的所有教程都指向 "MockMvc",但我无法编写 2 个以这种方式工作的测试。在几乎所有情况下,在我看来 安全性被完全忽略(MockMvc 即使没有给出任何用户也返回 200)。

假设我有以下设置,作为一个简单的例子:

安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }

}

控制器:

@RestController
public class TestController {

    @GetMapping("/test")
    public String getTest() {
        return "hello";
    }

}

属性:

spring.security.user.name=testuser
spring.security.user.password=testpassword

我可以像这样使用 "TestRestTemplate" 成功测试它:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DemoApplicationTests {

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    void when_userIsValid_should_return200() throws Exception {
        String res = testRestTemplate
                .withBasicAuth("testuser", "testpassword")
                .getForEntity("/test", String.class)
                .getBody();
        Assert.assertEquals("hello", res);
    }

    @Test
    void when_userIsInvalid_should_return401() throws Exception {
        HttpStatus res = testRestTemplate
                .withBasicAuth("foo", "bar")
                .getForEntity("/test", String.class)
                .getStatusCode();
        Assert.assertEquals(HttpStatus.UNAUTHORIZED, res);
    }

}

所以我的问题是:这是 "way to go" 吗?如果选择 MockMvc 工具,您能否提供一个工作示例?我已经尝试了来自 Tutorials 和 Whosebug 的 30 种解决方案并且 none 确实有效(MockMvc null,安全性被完全忽略,不再检测到控制器方法,我太愚蠢了,无法让它们工作:/)

提前致谢!

您可以使用 WebMvcTest 仅初始化控制器层(它不会 create/inject 所有其他 Spring beans 定义一个 service/repository,等等...)但它是适合(并且更快)测试控制器逻辑。

这是一个例子

@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = MainController.class)
public class ControllerTest  {

@Autowired
private MockMvc mockMvc;

//@MockBean
//Service service; // mock service dependencies if needed

@Test
public void invalidCredentials() throws Exception {

    this.mockMvc
            .perform(get("/test").header(HttpHeaders.AUTHORIZATION,
                    "Basic " + Base64Utils.encodeToString("testuser:WRONGpassword".getBytes())))
            .andExpect(status().isOk());
}