可以使用 MockMvc 测试 Spring 受安全保护的控制器吗?
Testing Spring Security protected Controllers with MockMvc possible?
我想弄清楚,什么是测试我的 Spring 启动应用程序安全配置的最佳方法。我的目标是进行两次测试:
- 给定用户 A,在 401 中访问资源/测试结果
- 给定用户 B,访问资源/测试结果为 200
开始我的研究时,我找到的所有教程都指向 "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());
}
我想弄清楚,什么是测试我的 Spring 启动应用程序安全配置的最佳方法。我的目标是进行两次测试:
- 给定用户 A,在 401 中访问资源/测试结果
- 给定用户 B,访问资源/测试结果为 200
开始我的研究时,我找到的所有教程都指向 "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());
}