如何让CSRF、DB连接、登录仅执行一次,重复运行待测试API?
一次性初始化+重复API测试实现方案
核心思路是把CSRF Token获取、数据库连接、登录这三个步骤放到测试套件的全局前置钩子中,让它们在整个测试流程启动时仅执行一次,后续所有测试用例直接复用初始化后的资源(比如认证Token、DB连接)来调用目标API。
以下是主流测试框架的具体实现示例:
1. Java JUnit 5
使用@BeforeAll注解标记初始化方法,该方法会在整个测试类的所有用例执行前仅运行一次:
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; public class APITestSuite { // 全局保存初始化后的资源 private static DBConnection dbConnection; private static String authToken; private static String csrfToken; @BeforeAll public static void initGlobalResources() { // 1. 获取CSRF Token csrfToken = CsrfUtils.fetchToken(); // 2. 建立数据库连接 dbConnection = DBConnector.create(); // 3. 执行登录获取认证Token authToken = AuthService.login(csrfToken, "testUser", "testPass"); } @Test public void testTargetAPI_Get() { // 复用全局资源调用目标API APIResponse response = TargetAPI.callGet(authToken, csrfToken); assert response.getStatusCode() == 200; } @Test public void testTargetAPI_Post() { APIResponse response = TargetAPI.callPost(authToken, csrfToken, new TestPayload()); assert response.getStatusCode() == 201; } // 省略工具类实现 private static class CsrfUtils { public static String fetchToken() { /* ... */ } } private static class DBConnector { public static DBConnection create() { /* ... */ } } private static class AuthService { public static String login(String csrf, String u, String p) { /* ... */ } } private static class TargetAPI { public static APIResponse callGet(String token, String csrf) { /* ... */ } public static APIResponse callPost(String token, String csrf, TestPayload payload) { /* ... */ } } }
2. Python Pytest
使用scope="session"的fixture,该fixture会在整个测试会话(所有测试文件/用例)中仅执行一次:
import pytest import requests @pytest.fixture(scope="session") def global_test_resources(): # 1. 获取CSRF Token csrf_res = requests.get("http://your-domain/csrf-token") csrf_token = csrf_res.cookies.get("csrf_token") # 2. 建立数据库连接 db_conn = get_db_connection() # 自定义数据库连接方法 # 3. 登录获取认证Token login_data = {"username": "test", "password": "test123", "csrf_token": csrf_token} login_res = requests.post("http://your-domain/login", data=login_data) auth_token = login_res.json()["auth_token"] # 返回复用资源 yield { "db_conn": db_conn, "auth_token": auth_token, "csrf_token": csrf_token } # 测试会话结束后清理资源 db_conn.close() def test_api_scenario_1(global_test_resources): headers = { "Authorization": f"Bearer {global_test_resources['auth_token']}", "X-CSRF-Token": global_test_resources['csrf_token'] } res = requests.get("http://your-domain/target-api", headers=headers) assert res.status_code == 200 def test_api_scenario_2(global_test_resources): headers = { "Authorization": f"Bearer {global_test_resources['auth_token']}", "X-CSRF-Token": global_test_resources['csrf_token'] } payload = {"data": "test-content"} res = requests.post("http://your-domain/target-api", headers=headers, json=payload) assert res.status_code == 201
3. JavaScript Mocha
使用根级别的before钩子,该钩子会在整个测试套件所有用例执行前仅运行一次:
const request = require('superagent'); const db = require('./db-connector'); // 全局资源变量 let dbConnection; let authToken; let csrfToken; // 全局初始化 before(async () => { // 1. 获取CSRF Token const csrfRes = await request.get('http://your-domain/api/csrf'); csrfToken = csrfRes.headers['x-csrf-token']; // 2. 建立数据库连接 dbConnection = await db.createConnection(); // 3. 登录获取Token const loginRes = await request.post('http://your-domain/api/login') .set('X-CSRF-Token', csrfToken) .send({ username: 'test', password: 'test123' }); authToken = loginRes.body.authToken; }); // 测试用例组 describe('Target API Tests', () => { it('should handle GET request', async () => { const res = await request.get('http://your-domain/api/target') .set('Authorization', `Bearer ${authToken}`) .set('X-CSRF-Token', csrfToken); res.should.have.status(200); }); it('should handle POST request', async () => { const res = await request.post('http://your-domain/api/target') .set('Authorization', `Bearer ${authToken}`) .set('X-CSRF-Token', csrfToken) .send({ content: 'test' }); res.should.have.status(201); }); }); // 全局清理 after(async () => { await dbConnection.close(); });
关键注意事项
- 资源清理:务必在测试会话结束后释放数据库连接等资源,避免内存泄漏。
- 状态隔离:如果多次调用API会修改服务器或数据库状态,需在每个测试用例执行前通过
@BeforeEach(JUnit)、scope="function"的fixture(Pytest)或beforeEach(Mocha)重置测试数据,确保用例之间互不干扰。 - 并行测试:若启用并行测试,需确认框架对全局初始化的隔离策略,部分框架会为每个并行进程/线程单独执行一次初始化,需根据需求调整配置。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

