大家可能都听说过“设计模式”这个词,有些人可能用过,有些人可能只是听说过。
我只是想分享我的一些关于如何在自动化测试框架中应用设计模式的经验,这将帮助你设计出一个这样的可扩展且易于维护的框架。
让我们以 Playwright 为例来理解这些概念就更容易了,它是当前市场上很流行的一个工具。为了方便理解,我将把每个模式分为四个部分,这样你就能轻松关联起来,并在你的日常工作中应用。
单例模式(Singleton Pattern) 真实例子想象你家里装了一个净水器。而不是在不同的房间里安装多个净水器,你只需要用一个,全家人都可以用。这不仅提高了效率,还避免不必要的重复。
技术说明单例模式保证在整个测试过程中只创建并重复使用一个 API 接口客户端实例,从而提升整体性能和一致性。
如何在日常工作中应用这些方法在测试 REST API 时,我们常常需要一个 API 客户端实例来发送请求时。而不是为每个测试都创建一个新的实例,我们可以使用这种单例模式。
这是一个API客户端类,用于从`https://api.example.com`获取API请求上下文。使用单例模式确保整个应用程序只使用一个API请求上下文实例。
class APIClient {
private static instance: APIRequestContext;
private constructor() {}
public static async getInstance(): Promise<APIRequestContext> {
if (!APIClient.instance) {
APIClient.instance = await request.newContext({ baseURL: 'https://api.example.com' });
}
// 获取API请求上下文的单例实例。
return APIClient.instance;
}
}
export default APIClient;
在測試中的使用方法
import { test } from '@playwright/test';
import APIClient from './APIClient';
test('测试 GET 请求', async () => {
const api = await APIClient.getInstance();
const response = await api.get('/users');
const responseBody = await response.json();
console.log(responseBody);
});
这样做能保证所有 API 请求在测试套件中使用同一个实例,避免重复创建 API 客户端。
## 如果不遵循这个模式,会发生什么?
* 不必要地创建了多个API客户端实例,导致**内存占用上升**。
* 由于冗余的设置操作,测试执行**速度变慢**。
* 多个实例管理不同的基础URL或认证令牌时,可能会出现**配置不一致**。
# 工厂方法
## 真实的非专业人士解释
想象一个在线订餐应用,你可以点一份**披萨、汉堡或通心粉**。你无需了解配方,只需选择你想吃的食物,系统就会帮你准备好。工厂方法可以根据需求动态生成不同的食物,允许根据特定请求创建对象。
## 技术说明
在 API 测试时,我们可以利用工厂方法模式来动态生成不同的 API 请求配置。
## ## 这在日常工作中如何应用
我们可以创建一个工厂,用来根据不同的端点和HTTP方法生成API请求。
import { APIRequestContext } from '@playwright/test';
class APIRequestFactory {
constructor(private apiContext: APIRequestContext) {}
async makeRequest(endpoint: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE', data?: any) {
switch (method) {
case 'GET':
return this.apiContext.get(endpoint);
case 'POST':
return this.apiContext.post(endpoint, { data });
case 'PUT':
return this.apiContext.put(endpoint, { data });
case 'DELETE':
return this.apiContext.delete(endpoint);
default:
throw new Error('不支持的 HTTP 请求方法');
}
}
}
**測試中的使用方法:**
import { test, request } from '@playwright/test';
import APIRequestFactory from './APIRequestFactory';
test('通过POST请求创建用户', async () => {
const apiContext = await request.newContext({ baseURL: 'https://api.example.com' });
const apiFactory = new APIRequestFactory(apiContext);
const response = await apiFactory.makeRequest('/users', 'POST', { name: 'John Doe', email: '[email protected]' }); // 用户端点
console.log(await response.json()); // 输出响应的JSON数据
});
这使 API 请求更灵活且便于重复使用。
如果不遵循此模式会怎样?
* 代码变得**重复冗余**,因为每个测试都有自己的请求创建逻辑。
* 如果端点结构发生变化,将**更难维护**。
* 缺乏**扩展性**,使得添加新的请求类型**变得比较困难**。
# 瑞典适配器模式
# 瑞典适配器模式应修正为:
# 瑞典适配器模式
# 适配器模式
## 真实的非专业人士解释
想想一个**USB-C到HDMI转换器**。你的笔记本电脑有一个**USB-C端口**,但你的显示器只接受**HDMI**。这个适配器可以帮助这两个不直接兼容的设备连接起来。
## 技术说明
当我们要将 Playwright API 测试集成到外部报告工具,例如 TestRail 时,我们可以使用适配器将 API 测试结果转换成 TestRail 能识别的格式。
## 工作日常中的应用
我们可以创建一个转换器,将 Playwright API 测试结果转成 TestRail 可用的格式。
class PlaywrightTestReport {
generate(): any {
return {
testCaseId: 101,
status: 'passed',
};
}
}
class TestRailAdapter {
constructor(private playwrightReport: PlaywrightTestReport) {}
generateTestRailFormat(): any {
const report = this.playwrightReport.generate();
return {
case_id: report.testCaseId,
status_id: report.status === 'passed' ? 1 : 5,
};
}
}
// 示例用法 /* 创建一个报告实例并生成TestRail格式的测试结果 */
const report = new PlaywrightTestReport();
const testRailAdapter = new TestRailAdapter(report);
console.log(testRailAdapter.generateTestRailFormat());
这使得将Playwright API测试的结果与TestRail的集成变得非常容易。
## 如果不遵循这种方式,会怎么样?
* 与外部系统**更难集成**。
* 需要进行**手动转换**,增加工作量并导致更多错误。
* 支持多个报表工具时会引发代码重复。
# 观察者模式(Observer 模式)
## 真实的非专业人士解释
想想你在**YouTube**上的订阅。当你关注了一个频道,每次有新视频上传时,你会自动收到通知。
## 技术说明
在API测试中,可以监控API请求的状态并自动触发后续动作。
## 如何在日常工作中使用:
我们可以创建一个监听器来监听API测试执行并实时记录结果。
class APIObserver {
// 用于存储所有订阅的监听器
private subscribers: ((event: string, data: any) => void)[] = [];
// 订阅一个监听器
subscribe(listener: (event: string, data: any) => void) {
this.subscribers.push(listener);
}
// 通知所有订阅的监听器
notify(event: string, data: any) {
this.subscribers.forEach((监听器) => 监听器(event, data));
}
}
## 如果不按照这个模式做会怎样?
* API 失败可能**悄悄发生**。
* **很难实时跟进**请求的执行。
* 导致**不太好的调试体验**。
# 外观模式
## 通俗解释
想想**酒店的礼宾员**。你只需要打个电话给礼宾员,他们就会帮你搞定一切。
## 简单来说,技术说明
一个**门面**(Facade)提供了一个简化接口,使访问复杂系统变得容易。在进行API测试时,我们可以通过使用门面来简化与多个API端点的交互过程。
## 日常工作中这能怎么用
我们可以创建一个易于使用的接口,来简化常见的 API 操作。
下面是一个用户API类,它包含获取用户信息和创建用户的方法。
class UserAPI {
constructor(private apiContext: APIRequestContext) {}
async getUser(userId: string) {
return this.apiContext.get(/users/${userId}
);
}
async createUser(data: any) {
return this.apiContext.post('/users', { data });
}
}
## 如果不按照这种模式来,会怎样?
* 代码变得**复杂**,需要直接与多个接口进行交互。
* **更难以管理**跨测试的 API 逻辑。
* 导致**测试用例中的代码重复**。
# 状态模式
## 简单易懂的解释
想想一个**红绿灯**。根据它是否是红灯、黄灯还是绿灯,司机的行为就会相应改变。灯的状态控制着交通,司机就会相应地调整他们的行为。
## 技术说明
状态模式(State Pattern)让对象能够根据其内部状态的变化改变其行为。在进行API测试时,我们可以根据不同的状态来决定是否重试API请求。
## 这在日常工作中如何使用
我们可以让系统这样运作,当系统处于“重试”状态时自动重试 API 请求。
class API请求状态 {
constructor(private api请求上下文: API请求上下文) {}
async 发起请求(endpoint: string) {
let response = await this.api请求上下文.get(endpoint);
if (response.status() === 500) {
console.log('重试请求...');
response = await this.api请求上下文.get(endpoint);
}
return response;
}
}
## 如果不按照这个模式来会发生什么?
* 代码变得**僵化**,难以修改和维护。
* **难以高效管理**重试逻辑,使之变得繁琐。
* 未处理的瞬时失败增加了**测试不稳定的几率**。
结论:不遵循这些规则,并不意味着你不能创建一个测试自动化框架。这些模式能帮助你构建一个更强大、更易维护、更灵活且可扩展性的框架。这并不是一个完整的列表,但这是我设计框架时更常使用的模式。
共同學習,寫下你的評論
評論加載中...
作者其他優質文章