测试后如何重置Docker中配置的Redis数据库以清除残留令牌?
解决测试间Redis令牌残留导致的测试失败问题
问题背景
测试时将用户访问令牌存储在Docker容器的Redis中,首次测试正常,但因无法重置容器,令牌会在测试间残留,导致用户会话持续存在,引发后续测试失败。该令牌配合AsyncBearerAuthenticator使用,用于校验请求头中的令牌是否能通过指定路由的身份验证。
已实现辅助方法在测试时存入令牌,但需要在每次测试后删除令牌或重置数据库。
现有代码
测试辅助方法
extension Application { @discardableResult func test( _ method: HTTPMethod, _ path: String, user: UserModel? = .none, tokenProtected: Bool = true, content: (any Content)? = .none, afterResponse: (XCTHTTPResponse) throws -> () = { _ in }, file: StaticString = #file, line: UInt = #line ) async throws -> XCTApplicationTester { var headers: HTTPHeaders = [:] if let user, tokenProtected { let accessToken = try AccessTokenModel.generate(for: user) try await self.redis.set(RedisKey(accessToken.value), toJSON: accessToken) headers.add(name: "Authorization", value: "Bearer \(accessToken.value)") } return try test( method, path, headers: headers, file: file, line: line, beforeRequest: { if let content { try $0.content.encode(content) }}, afterResponse: afterResponse ) } }
Redis配置(configure.swift)
app.redis.configuration = try RedisConfiguration(hostname: "localhost", port: 6380) app.sessions.use(.redis)
Redis Docker启动命令
docker run --name myapp_redis_testing -p 6380:6379 -d redis
解决方案
方案1:每次测试后删除当前令牌
修改测试辅助方法,在afterResponse回调中添加令牌删除逻辑,确保测试完成后清理当前生成的令牌:
extension Application { @discardableResult func test( _ method: HTTPMethod, _ path: String, user: UserModel? = .none, tokenProtected: Bool = true, content: (any Content)? = .none, afterResponse: (XCTHTTPResponse) throws -> () = { _ in }, file: StaticString = #file, line: UInt = #line ) async throws -> XCTApplicationTester { var headers: HTTPHeaders = [:] var generatedAccessToken: AccessTokenModel? = nil if let user, tokenProtected { let accessToken = try AccessTokenModel.generate(for: user) try await self.redis.set(RedisKey(accessToken.value), toJSON: accessToken) headers.add(name: "Authorization", value: "Bearer \(accessToken.value)") generatedAccessToken = accessToken } return try test( method, path, headers: headers, file: file, line: line, beforeRequest: { if let content { try $0.content.encode(content) }}, afterResponse: { response in try afterResponse(response) // 清理当前测试生成的令牌 if let token = generatedAccessToken { try await self.redis.delete(RedisKey(token.value)) } } ) } }
方案2:测试前后重置Redis数据库
如果需要彻底清空Redis(比如测试间有其他会话数据残留),可以在测试套件的setUp或tearDown方法中执行Redis的FLUSHDB命令:
final class MyAppTests: XCTestCase { var app: Application! override func setUp() async throws { try await super.setUp() app = Application(.testing) try configure(app) // 测试前清空Redis数据库 try await app.redis.send(.flushDB) } override func tearDown() async throws { // 测试后清空Redis数据库(可选,根据需求选择在setUp或tearDown执行) try await app.redis.send(.flushDB) app.shutdown() try await super.tearDown() } // 测试用例... }
方案3:为测试使用独立的Redis数据库
Redis默认有16个数据库,可以为测试指定单独的数据库,避免与其他环境冲突,同时清空时不影响其他数据:
- 修改
configure.swift中的Redis配置,指定数据库编号:
app.redis.configuration = try RedisConfiguration(hostname: "localhost", port: 6380, database: 1) // 使用数据库1 app.sessions.use(.redis)
- 在测试的
setUp或tearDown中清空该数据库:
try await app.redis.send(.flushDB)
方案4:Docker容器级别重置
如果需要彻底重置容器,可以在测试脚本中添加Docker命令,每次测试前重启并清空容器:
# 停止并删除现有容器 docker stop myapp_redis_testing && docker rm myapp_redis_testing # 重新创建容器 docker run --name myapp_redis_testing -p 6380:6379 -d redis
可以将上述命令集成到测试的前置脚本中,比如在Xcode的Scheme预动作中添加,或者使用Makefile管理测试流程。
总结
- 若只需清理当前测试生成的令牌,方案1最轻量化;
- 若测试间有其他Redis数据残留,方案2或3更彻底;
- 若需要完全隔离测试环境,方案4适合集成到自动化测试流程中。
内容的提问来源于stack exchange,提问作者Roland Lariotte
相关产品推荐
相关产品推荐

