Spring Security 测试实战

引言

试题管理系统的安全模块使用 Spring Security
代码从原华软仓库移植,在移植的过程中,发现原测试编写的不好,遂在新系统中对安全模块测试进行了重构。

Spring 测试

添加 @SpringBootTest
注解,意为这是一个基于 SpringBoot
单元测试

SpringBoot
在官方的 Guide
中提供了多种测试方式。

@SpringBootTest
注解中的 webEnvironment
属性可以配置测试环境,默认为 MOCK
环境。

/**
 * The type of web environment to create when applicable. Defaults to
 * {@link WebEnvironment#MOCK}.
 * @return the type of web environment
 */
WebEnvironment webEnvironment() default WebEnvironment.MOCK;

模拟环境测试

启用 Spring Security
后,单元测试中对 api
的测试会被 Spring Security
Filter
进行拦截,所以测试之前需要进行用户登录操作。

之前都是使用比较笨重的方法,写一个 @Before
@Before
里进行登录,之后再执行测试方法。

最近在阅读 Spring Security Test
文档之后,终于找到一种模拟登录十分简便的方法, @WithMockUser

test method with mock user – spring security test

引入 Spring Security Test
依赖:

<!-- Spring Security Test -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

示例代码如下:

@SpringBootTest
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@WithMockUser(username = "admin", password = "admin")
public class ControllerTest {

    @Autowired
    protected MockMvc mockMvc;

    @Test
    void contextLoads() {
    }
}

注: @RunWith(SpringRunner.class)
表示当前测试使用 org.springframework.test.context.junit4.SpringRunner
类来执行,最新的 SpringBoot
版本中已经全面启用 junit5
,不推荐使用 junit4.SpringRunner
,因为未经过内部学习与测试,未在生产项目中使用。

真实环境测试

为了减少学习与沟通的成本,之前,所有的测试规定都在 MOCK
环境下,使用 MockMVC
进行 api
测试。

虽然 MOCK
环境能解决大部分的问题,并且可以在不启动 Server
的情况下直接进行测试,但在某些场景下,仍需要真实环境下的 HTTP
服务与请求测试。

启用 Spring Security
后, MockMVC
是直接测试控制器,并非在真实的 HTTP
服务器下进行测试, MOCK
环境中使用的是 MockHttpSession
,这不是标准的 Session
实现,没有加入对 COOKIE
的支持,所以在测试安全模块时,无法像浏览器一样测试 COOKIE
认证信息。

spring mockmvc doesn’t contain cookies – stackoverflow

StackOverflow
上也没有解决方案,答案推荐使用 TestRestTemplate
+真实的服务器环境进行单元测试。

webEnvironment
配置为 SpringBootTest.WebEnvironment.RANDOM_PORT
,即表示当前测试在一个随机端口的真实 Web
环境下运行。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class AuthControllerTest {
    @Autowired
    private TestRestTemplate restTemplate;
}

测试时使用 TestRestTemplate
进行网络请求的发送,真实模拟 Web
服务器环境。

示例代码如下:

logger.debug("3: 测试用户名密码正确");
username = RIGHT_USERNAME;
password = RIGHT_PASSWORD;
response = this.restTemplate
        .withBasicAuth(username, password)
        .getForEntity(CONFIG_LOGIN, Void.class);

logger.debug("断言: 状态码为200");
assertThat(response.getStatusCode().value()).isEqualTo(HttpStatus.OK.value());

logger.debug("获取 response 的 Set-Cookie 信息,并断言");
String setCookie = response.getHeaders().getFirst(HttpHeaders.SET_COOKIE);
assertThat(setCookie).isNotNull();

总结

两个各有优点,之前我们一直使用简单方便的 Mock
环境进行测试,但当我们有一天,发现这个 Mock
环境测试下的 MockHttpSession
无法满足需求的时候,我们开始探索其他的测试方案。

真正的掌握,不是知道什么时候用,而是知道什么时候不用。

原文 

https://segmentfault.com/a/1190000021122222

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Spring Security 测试实战

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址