测试自动化中的设计模式

2025-08-12   出处: Mediam  作/译者:HariPrasath/溜的一比

测试自动化中的设计模式

我们可能都听说过设计模式,有些可能用过,有些至少听说过。

我想分享一些关于在测试自动化框架中使用设计模式的知识,这将帮助你设计一个出色的、可扩展且易于维护的框架。

让我们以 Playwright 为例,这是目前市场上流行的工具,来理解这些概念。为了便于理解,我将每个模式分为四个部分,以便你可以轻松地将其应用到日常工作中。

单例模式

现实生活中的例子

想象一下你家里有一个净水器。与其在不同的房间里安装多个净水器,不如只装一个供全家使用。这既保证了效率,又避免了不必要的重复。

技术解释

单例模式确保只创建一个 API 客户端实例,并在多个测试用例中重复使用,从而提高性能和一致性。

在日常工作中的应用

在测试 REST API 时,我们通常需要一个单一的 API 客户端实例来发送请求。与其为每个测试创建一个新实例,不如使用单例模式。

import { request, APIRequestContext } from '@playwright/test';

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' });
    }
    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: 'john@example.com' });
  console.log(await response.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,
    };
  }
}

// 使用
const report = new PlaywrightTestReport();
const testRailAdapter = new TestRailAdapter(report);
console.log(testRailAdapter.generateTestRailFormat());

这使得将 Playwright API 测试结果与 TestRail 集成变得容易。

不遵循该模式的后果
  • 与外部系统集成变得困难。
  • 手动转换会增加工作量和错误。
  • 在支持多个报告工具时会导致代码重复。

观察者模式

现实生活中的通俗解释

想象一下 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((listener) => listener(event, data));
  }
}
不遵循该模式的后果
  • 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 逻辑变得更加困难。
  • 测试用例中代码重复。

状态模式

现实生活中的通俗解释

想象一个交通灯。根据是红灯、黄灯还是绿灯,司机的行为会有所不同。灯控制状态,司机相应地跟随。

技术解释

状态模式允许对象在内部状态变化时改变其行为。在 API 测试中,我们可以使用这种模式根据不同的状态处理 API 请求重试。

在日常工作中的应用

我们可以创建一个系统,当处于 “重试” 状态时重试 API 调用。

class APIRequestState {
  constructor(private apiContext: APIRequestContext) {}
  async makeRequest(endpoint: string) {
    let response = await this.apiContext.get(endpoint);
    if (response.status() === 500) {
      console.log('正在重试请求...');
      response = await this.apiContext.get(endpoint);
    }
    return response;
  }
}
不遵循该模式的后果
  • 代码变得僵硬,难以修改。
  • 难以高效地管理重试逻辑。
  • 由于未处理的瞬态故障,测试易碎性增加。
结论

没有这些模式,你当然也可以创建一个测试自动化框架。这是可能的。但这些模式将帮助你构建一个强大、可维护、可扩展且灵活的框架。这并不是一个完整的列表,而是我在设计框架时更多使用的模式。


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
/47 人阅读/0 条评论 发表评论

登录 后发表评论
最新文章