在2023使用playwright进行自动化测试

playwright一直是我最看好的新一代自动化测试框架,2022年底playwright在npm上的下载量超过了100万,尽管不如selenium和cypress,不过势头还是相当强劲的。最近正好发现一篇文章简单的介绍了使用typescript,pageobject和fixture配合playwright进行用例编写的文章,这里把里面的精华拿出来分享一下。

老生常谈,playwright的优势

  • 有个好爹,微软出品,看好长期更新维护和迭代,但也可能突然被砍掉,毕竟大公司都在裁员
  • 运行速度快
  • 自动等待元素出现
  • 报告的呈现很多元化,可以设置重试机制,捕获执行日志,截屏录屏等
  • 支持多个浏览器并行执行
  • 提供自动生成代码能力以及Inspector GUI
  • 一套代码,跨浏览器执行的能力

目录结构

框架整体的目录结构如下。

.

├── config 
│   ├── global-setup.ts 
│   └── playwright.config.ts 
├── package-lock.json 
├── package.json 
└── src 
    ├── data 
    │   └── data.json 
    ├── fixtures 
    │   ├── AxeFixture.ts 
    │   └── TodoFixture.ts 
    ├── pages 
    │   └── TodoPage.ts 
    └── tests 
        ├── a11y.spec.ts 
        └── demo-pom-todo-app.spec.ts 

config目录

playwright.config.ts playwright的配置文件

global-setup.ts 在所有用例执行前运行一次,主要的目的是登录一次被测系统并保存浏览器的全局状态到storageState.json文件中。这样就不需要每个用例都去单独登录一次了。更多信息可以参考文档。https://playwright.dev/docs/test-advanced#global-setup-and-teardown

Page Object

po基本上是自建框架的必选项了。具体的实现如下

import { expect, Locator, Page } from '@playwright/test'; 
 
export class TodoDemoPage { 
  readonly page: Page; 
  readonly newTodoInput: Locator; 
  readonly todoTitle: Locator; 
  readonly todoCount: Locator 
 
  constructor(page: Page) { 
    this.page = page; 
    this.newTodoInput = page.getByPlaceholder('What needs to be done?'); 
    this.todoTitle = page.getByTestId('todo-title'); 
    this.todoCount = page.getByTestId('todo-count'); 
  } 
 
  async goto() { 
    await this.page.goto('https://demo.playwright.dev/todomvc'); 
  } 
 
  async addTodo(data: string) { 
    await this.newTodoInput.fill(data) 
    await this.newTodoInput.press("Enter") 
  } 
 
  async addDefaultTodos(todosItems: string[]) { 
    for (const todo of todosItems) { 
      await this.addTodo(todo) 
    } 
  } 
... 
} 

关于po需要注意几点

  • 命名规则,确保页面上的元素和一些页面方法都有合适的名称
  • 一个方法只做一件事情,而且可以通过方法名推测出来
  • 对页面呈现的一些结果进行断言
  • dry,don’t repeat yourself

Fixtures

fixture可以简单理解为准备数据,设置上下文环境

import { test as base } from '@playwright/test'; 
import { TodoDemoPage } from '../pages/TodoPage'; 
 
type MyFixtures = { 
  todoDemoPage: TodoDemoPage; 
  noneExistingPage: any 
}; 
 
export const todoDemoPage = async({page}, use) => { 
  const todoDemoPage = new TodoDemoPage(page); 
  // Set up the fixture. 
  await todoDemoPage.goto(); 
  // Use the fixture value in the test. 
  await use(todoDemoPage); 
} 
 
// we can create as many fixtures as we want, but I prefer to store them in separate files 
export const noneExistingPage = async({page}, use) => { 
  // Let's imagine we have another fixter-page set up here 
} 
 
export const test = base.extend({todoDemoPage, noneExistingPage}); 

上面的代码其实就是创建了TotoDemoPage,后面用例里就可以直接使用这个页面了。

fixture的好处还是很多的。

fixture让setup和teardown钩子函数在同一个地方进行定义,这样就比较好维护了

  • fixture可以重复使用
  • fixture按需使用,定义了你也可以不用
  • fixture可以组合使用

测试用例

用例相对就比较简单的,因为难的部分已经搞完了。

import { test } from '../fixtures/TodoFixture' 
 
const TODO_ITEMS = [ 
    'buy some cheese', 
    'buy bottle of wine, or two', 
    'celebrate' 
]; 
 
// our test is imported from fixtures folder 
// so we can have access to tododDempPage and noneExistingPage objects 
// in callback function trhough destructuring and we can use it for our needs 
test.describe('New Todo', () => { 
  test('should allow me to add todo items', async ({ todoDemoPage }) => { 
    await todoDemoPage.addTodo(TODO_ITEMS[0]) 
    await todoDemoPage.checkInputIsEmpty(); 
    await todoDemoPage.addTodo(TODO_ITEMS[1]) 
    await todoDemoPage.checkAddedTodos([TODO_ITEMS[0], TODO_ITEMS[1]]) 
    await todoDemoPage.checkNumberOfTodosInLocalStorage(2); 
  }); 
 
  test('should clear text input field when an item is added', async ({ todoDemoPage }) => { 
    await todoDemoPage.addTodo(TODO_ITEMS[0]) 
    await todoDemoPage.checkInputIsEmpty(); 
    await todoDemoPage.checkNumberOfTodosInLocalStorage(1); 
  }); 
 
  test('should append new items to the bottom of the list', async ({ todoDemoPage }) => { 
    await todoDemoPage.addDefaultTodos(TODO_ITEMS); 
    await todoDemoPage.checkDefaultAddedTodods(TODO_ITEMS); 
    await todoDemoPage.checkAddedTodos(TODO_ITEMS) 
    await todoDemoPage.checkNumberOfTodosInLocalStorage(3); 
  }); 
}); 

用例很简洁易懂对吧。这里断言都封装在了page object里,所以整个流程全是对po实例进行调用,很统一,不过我不是很喜欢这种方式,我更喜欢把原生断言放在用例里,这样po层会更简洁一些,要不需要绞尽脑汁去给封装断言的方法取名。

CICD

可以在官方文档找到方法。https://playwright.dev/docs/ci

总结

https://github.com/eugeniuszG/playwright-starter 这里有框架模板,大家可以下载下来进行二次开发,最后感谢作者的总结和示例。

最后: 下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取 【保证100%免费】
在2023使用playwright进行自动化测试_第1张图片

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!
在这里插入图片描述

你可能感兴趣的:(IT,程序员,软件测试,json,npm,webpack,自动化测试,软件测试)