前言
闲来无事,不小心接触到了cucumber自动化测试框架,于是上网查了一下,国内关于这个框架的内容竟然很少。
索性自己补充一下,也是学习的总结吧。
-项目模板弄好,下载即食(后面有链接。。。)
先搞清楚这个东西是什么?
Cucumber 是一个用于行为驱动开发(Behavior Driven Development, BDD)的工具,是一个自动化测试框架。
它最初是为 Ruby 设计的,但现在已被移植到了多种编程语言中,包括 Java、JavaScript、.NET 等。
Cucumber 的核心理念是让非技术人员(如产品经理、业务分析师)也能参与到软件开发的过程中,通过自然语言来描述软件的行为,
从而增强团队之间的沟通。
好了,总结就是简单版的自动化测试用的框架,跟selenium,playwright差不多。
来!直接上手项目,看项目学的最快。
这个项目是基于Cucumber框架进行行为驱动开发(BDD),并使用WebdriverIO作为前端自动化测试框架。
先说说cucumber的一些基础信息。
主要就包含两个重要的部分:feature文件和定义步骤的step文件
-
feature文件
长这样!
1. **Given**:
- 表示测试的前提条件或者初始状态。
- 它描述的是在执行任何动作之前系统应该处于的状态。
- 例如,“Given I am logged into my account”意味着测试开始前,用户应当已成功登录到他们的账户。
2. **When**:
- 描述用户采取的动作或触发某个事件的操作。
- 这个部分通常包含用户的交互行为,比如点击按钮、填写表单字段等。
- 例如,“When I click the 'Submit' button”意味着用户点击了提交按钮。
3. **Then**:
- 描述期望的结果或系统的响应。
- 这里会列出对用户操作的预期反应,包括界面变化、数据更新等。
- 例如,“Then I should see a success message”意味着用户应能看到一条成功的提示信息。
</aside>
-
既然展示了测试流程,也要定义测试步骤,怎么定义如下:
webdriverIO写好了很多基础的函数,一路导入写进去即可。
举个运行例子:怎么在百度页面输入恭喜你并截图。
很简单吧 一图看懂
测试结果
下面就是怎么从0做一个cucumber+webdriverIO的项目,去完成一些自动化测试的demo,或者你也可以拿来爬虫?看你咯
1.基础准备
node的安装
1、下载和安装Node.js
(1)下载路径:https://nodejs.org/zh-cn/
建议下载与操作系统对应的LTS版,即长期维护版。
(2)成功安装Node.js后,在命令行窗口中,运行命令node -v,
若能看到Node.js的版本信息,则表示Node.js已正常安装。
2.配置node的镜像源 安装快一点
npm config set registry https://registry.npmmirror.com
3.查看镜像源
npm config get registry
浏览器驱动的安装
浏览器驱动-> 用来自动操作网页的工具
参考下面链接
详解Chrome驱动安装步骤:版本选择与配置全解析_谷歌浏览器驱动-CSDN博客
2.初始化一个node项目
这一步很简单,idea 里面创建一个空项目,然后打开命令行输入下面初始化命令
npm init -y
#出现一个package.json文件 是一个依赖文件
修改package.json内容如下
{
"name": "xz-test2",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"clean": "read -p \"Are you sure you want to clean the project? [y/n] \" REPLY; if [[ $REPLY =~ ^[Yy]$ ]]; then rm -R .git .github demo-app test .codeclimate.yml .travis.yml jest.json wdio.BUILD.conf.js src/features/**; fi",
"test": "run-s test:*",
"test:lint": "eslint 'src/**/*.ts' 'test/**/*.js!(setup.js)'",
"test:unit": "jest --config=jest.config.cjs --detectOpenHandles",
"test:features": "wdio run wdio.BUILD.conf.ts",
"wdio": "wdio run wdio.BUILD.conf.ts"
},
"keywords": ["wdio",
"webdriver",
"webdriverio",
"cucumber",
"test",
"boilerplate",
"selenium"],
"devDependencies": {
"@types/jest": "^29.5.13",
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"@wdio/cli": "9.1.2",
"@wdio/config": "9.1.2",
"@wdio/cucumber-framework": "9.1.2",
"@wdio/globals": "9.1.2",
"@wdio/local-runner": "9.1.2",
"@wdio/spec-reporter": "9.1.2",
"@wdio/static-server-service": "9.1.2",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-wdio": "^9.0.8",
"http-server": "^14.1.1",
"jest": "^29.7.0",
"jest-circus": "^29.7.0",
"npm-run-all2": "^6.2.3",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.6.2",
"webdriverio": "9.1.2"
},
"author": "",
"license": "ISC",
"description": ""
}
使用npm install去下载依赖 ,出现node-modules文件即可
3.配置webdriverIO的配置文件
在项目文件下新建个wdio.comf.json文件,内容如下:
import url from 'node:url';
import path from 'node:path';
import { hooks } from './src/support/hooks.js';
const dirname = url.fileURLToPath(new URL('.', import.meta.url));
export const config: WebdriverIO.Config = {
//
// ====================
// Runner Configuration
// ====================
//
// WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
// on a remote machine).
runner: 'local',
//
// ==================
// Specify Test Files
// ==================
// Define which test specs should run. The pattern is relative to the directory
// from which `wdio` was called. Notice that, if you are calling `wdio` from an
// NPM script (see https://docs.npmjs.com/cli/run-script) then the current working
// directory is where your package.json resides, so `wdio` will be called from there.
//
specs: [
'./src/features/**/*.feature',
],
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
],
//
// ============
// Capabilities
// ============
// Define your capabilities here. WebdriverIO can run multiple capabilities at the same
// time. Depending on the number of capabilities, WebdriverIO launches several test
// sessions. Within your capabilities you can overwrite the spec and exclude options in
// order to group specific specs to a specific capability.
//
// First, you can define how many instances should be started at the same time. Let's
// say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
// set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
// files and you set maxInstances to 10, all spec files will get tested at the same time
// and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests.
//
// maxInstances: 5,
//
// If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities:
// https://docs.saucelabs.com/basics/platform-configurator/
//
capabilities: [{
// maxInstances can get overwritten per capability. So if you have an in-house Selenium
// grid with only 5 firefox instances available you can make sure that not more than
// 5 instances get started at a time.
maxInstances: 5,
//
browserName: 'chrome',
// If outputDir is provided WebdriverIO can capture driver session logs
// it is possible to configure which logTypes to include/exclude.
// excludeDriverLogs: ['*'], // pass '*' to exclude all driver session logs
// excludeDriverLogs: ['bugreport', 'server'],
}],
//
// ===================
// Test Configurations
// ===================
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: 'trace',
outputDir: path.join(dirname, '/logs'),
//
// Set specific log levels per logger
// loggers:
// - webdriver, webdriverio
// - @wdio/applitools-service, @wdio/browserstack-service,
// @wdio/devtools-service, @wdio/sauce-service
// - @wdio/mocha-framework, @wdio/jasmine-framework
// - @wdio/local-runner, @wdio/lambda-runner
// - @wdio/sumologic-reporter
// - @wdio/cli, @wdio/config, @wdio/sync, @wdio/utils
// Level of logging verbosity: trace | debug | info | warn | error | silent
// logLevels: {
// webdriver: 'info',
// '@wdio/applitools-service': 'info'
// },
//
// If you only want to run your tests until a specific amount of tests have failed use
// bail (default is 0 - don't bail, run all tests).
bail: 0,
//
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
// gets prepended directly.
baseUrl: 'http://localhost:8080',
//
// Default timeout for all waitFor* commands.
waitforTimeout: 10000,
//
// Default timeout in milliseconds for request
// if browser driver or grid doesn't send response
connectionRetryTimeout: 90000,
//
// Default request retries count
connectionRetryCount: 3,
//
// Test runner services
// Services take over a specific job you don't want to take care of. They enhance
// your test setup with almost no effort. Unlike plugins, they don't add new
// commands. Instead, they hook themselves up into the test process.
// services: [],
//
// Framework you want to run your specs with.
// The following are supported: Mocha, Jasmine, and Cucumber
// see also: https://webdriver.io/docs/frameworks.html
//
// Make sure you have the wdio adapter package for the specific framework installed
// before running any tests.
framework: 'cucumber',
//
// The number of times to retry the entire specfile when it fails as a whole
// specFileRetries: 1,
//
// Whether or not retried specfiles should be retried immediately or deferred
// to the end of the queue specFileRetriesDeferred: false,
//
// Test reporter for stdout.
// The only one supported by default is 'dot'
// see also: https://webdriver.io/docs/dot-reporter.html
reporters: ['spec'],
//
// If you are using Cucumber you need to specify the location of your step definitions.
cucumberOpts: {
// <boolean> show full backtrace for errors
backtrace: false,
// <string[]> module used for processing required features
requireModule: [],
// <boolean< Treat ambiguous definitions as errors
failAmbiguousDefinitions: true,
// <boolean> invoke formatters without executing steps
// dryRun: false,
// <boolean> abort the run on first failure
failFast: false,
// <boolean> Enable this config to treat undefined definitions as
// warnings
ignoreUndefinedDefinitions: false,
// <string[]> ("extension:module") require files with the given
// EXTENSION after requiring MODULE (repeatable)
names: [],
// <boolean> hide step definition snippets for pending steps
snippets: true,
// <boolean> hide source uris
source: true,
// <string[]> (name) specify the profile to use
profile: [],
// <string[]> (file/dir) require files before executing features
require: [
'./src/steps/given.ts',
'./src/steps/then.ts',
'./src/steps/when.ts',
// Or search a (sub)folder for JS files with a wildcard
// works since version 1.1 of the wdio-cucumber-framework
// './src/**/*.js',
],
scenarioLevelReporter: false,
order: 'defined',
// <string> specify a custom snippet syntax
snippetSyntax: undefined,
// <boolean> fail if there are any undefined or pending steps
strict: true,
// <string> (expression) only execute the features or scenarios with
// tags matching the expression, see
// https://docs.cucumber.io/tag-expressions/
tagExpression: 'not @Pending',
// <boolean> add cucumber tags to feature or scenario name
tagsInTitle: false,
// <number> timeout for step definitions
timeout: 20000,
} as WebdriverIO.CucumberOpts,
...hooks,
};
4.最后是创建文件架构如下:
- .idea:IntelliJ IDEA的配置文件夹。
- logs:日志文件夹,用于存储运行时的日志信息。
- node_modules:Node.js模块安装目录,包含了项目依赖的所有第三方库。
- src:
- features:功能特性文件夹,通常包含Gherkin格式的测试用例(
.feature
文件)。 - steps:步骤定义文件夹,包含与Gherkin测试用例对应的实现代码。
- given.ts: 定义给定条件的步骤。
- then.ts: 定义然后/结果的步骤。
- when.ts: 定义当/动作的步骤。
- features:功能特性文件夹,通常包含Gherkin格式的测试用例(
- support:支持文件夹,包含辅助类、函数等。
- action:操作相关的辅助类或函数。
- check:检查相关的方法或函数。
- lib:通用库或工具方法。
- screenshots:截图文件夹,用于保存测试过程中生成的截图。
- hooks.ts: 测试钩子文件,可以在这里定义测试前后的钩子函数。
- package.json: 项目配置文件,描述了项目的基本信息和依赖关系。
- package-lock.json: 包锁定文件,记录了具体版本的依赖项。
- wdio.conf.ts: WebdriverIO配置文件,用于设置测试环境和浏览器驱动。
- xz-test2.iml: IntelliJ IDEA的项目索引文件。
!!!文件src内容自己写,我是站在前人的肩膀上已经准备好了一些基础的步骤代码,如果你也不想写基础的像什么打开链接,点击按钮等基础步骤。你可以直接复制我的src文件到你的项目里面。以下是下载文件链接。
链接:https://pan.baidu.com/s/1pJmdGydVmOLLSDNVs9KtJw?pwd=1314
提取码:1314
–来自百度网盘超级会员V4的分享
已完成但不限于下面内容
Given steps 给定步骤
I open the (url|site) "([^"]*)?"
Open a site in the current browser window/tab
在当前浏览器窗口/选项卡中打开站点
the element "([^"]*)?" is( not)* displayed
Check the (in)visibility of an element
检查元素的 (in) 可见性
the element "([^"]*)?" is( not)* enabled
Check if an element is (not) enabled
检查元素是否已启用
the element "([^"]*)?" is( not)* selected
Check if an element is (not) selected
检查元素是否已选中
the checkbox "([^"]*)?" is( not)* checked
Check if a checkbox is (not) checked
检查复选框是否被选中(未)
there is (an|no) element "([^"]*)?" on the page
Check if an element (does not) exist
检查元素是否(不存在)
the title is( not)* "([^"]*)?"
Check the title of the current browser window/tab
检查当前浏览器窗口/选项卡的标题
the element "([^"]*)?" contains( not)* the same text as element "([^"]*)?"
Compare the text of two elements
比较两个元素的文本
the (button|element) "([^"]*)?"( not)* contains the text "([^"]*)?"
Check if an element contains the given text
检查元素是否包含给定的文本
the (button|element) "([^"]*)?"( not)* contains any text
Check if an element does not contain any text
检查元素是否不包含任何文本
the (button|element) "([^"]*)?" is( not)* empty
Check if an element is empty
检查元素是否为空
the page url is( not)* "([^"]*)?"
Check the url of the current browser window/tab
检查当前浏览器窗口/选项卡的 url
the( css)* attribute "([^"]*)?" from element "([^"]*)?" is( not)* "([^"]*)?"
Check the value of an element's (css) attribute
检查元素的 (css) 属性的值
the cookie "([^"]*)?" contains( not)* the value "([^"]*)?"
Check the value of a cookie
检查 Cookie 的值
the cookie "([^"]*)?" does( not)* exist
Check the existence of a cookie
检查 Cookie 是否存在
the element "([^"]*)?" is( not)* ([\d]+)px (broad|tall)
Check the width/height of an element
检查元素的宽度/高度
the element "([^"]*)?" is( not)* positioned at ([\d]+)px on the (x|y) axis
Check the position of an element
检查元素的位置
I have a screen that is ([\d]+) by ([\d]+) pixels
Set the browser size to a given size
将浏览器大小设置为给定大小
I have closed all but the first (window|tab)
Close all but the first browser window/tab
关闭除第一个浏览器窗口/选项卡之外的所有浏览器窗口/选项卡
a (alertbox|confirmbox|prompt) is( not)* opened
Check if a modal is opened
检查是否打开了模态框
Then steps 然后步骤
I expect that the title is( not)* "([^"]*)?"
Check the title of the current browser window/tab
检查当前浏览器窗口/选项卡的标题
I expect that element "([^"]*)?" does( not)* appear exactly "([^"]*)?" times
Checks that the element is on the page a specific number of times
检查元素是否在页面上显示特定次数
I expect that element "([^"]*)?" is( not)* visible
Check if a certain element is visible
检查某个元素是否可见
I expect that element "([^"]*)?" becomes( not)* visible
Check if a certain element becomes visible
检查某个元素是否可见
I expect that element "([^"]*)?" is( not)* within the viewport
Check if a certain element is within the current viewport
检查某个元素是否在当前视区内
I expect that element "([^"]*)?" does( not)* exist
Check if a certain element exists
检查某个元素是否存在
I expect that element "([^"]*)?"( not)* contains the same text as element "([^"]*)?"
Compare the text of two elements
比较两个元素的文本
I expect that (button|element) "([^"]*)?"( not)* contains the text "([^"]*)?"
Check if an element or input field contains the given text
检查元素或输入字段是否包含给定的文本
I expect that (button|element) "([^"]*)?"( not)* contains any text
Check if an element or input field contains any text
检查元素或输入字段是否包含任何文本
I expect that (button|elementelement) "([^"]*)?" is( not)* empty
Check if an element or input field is empty
检查元素或输入字段是否为空
I expect that the url is( not)* "([^"]*)?"
Check if the the URL of the current browser window/tab is a certain string
检查当前浏览器窗口/选项卡的 URL 是否为某个字符串
I expect that the path is( not)* "([^"]*)?"
Check if the path of the URL of the current browser window/tab is a certain string
检查当前浏览器窗口/标签页的 URL 路径是否为某个字符串
I expect the url to( not)* contain "([^"]*)?"
Check if the URL of the current browser window/tab contains a certain string
检查当前浏览器窗口/选项卡的 URL 是否包含某个字符串
I expect that the( css)* attribute "([^"]*)?" from element "([^"]*)?" is( not)* "([^"]*)?"
Check the value of an element's (css) attribute
检查元素的 (css) 属性的值
I expect that checkbox "([^"]*)?" is( not)* checked
Check if a check-box is (not) checked
检查复选框是否被选中(未)
I expect that element "([^"]*)?" is( not)* selected
Check if an element is (not) selected
检查元素是否已选中
I expect that element "([^"]*)?" is( not)* enabled
Check if an element is (not) enabled
检查元素是否已启用
I expect that cookie "([^"]*)?"( not)* contains "([^"]*)?"
Check if a cookie with a certain name contains a certain value
检查具有特定名称的 Cookie 是否包含特定值
I expect that cookie "([^"]*)?"( not)* exists
Check if a cookie with a certain name exist
检查是否存在具有特定名称的 Cookie
I expect that element "([^"]*)?" is( not)* ([\d]+)px (broad|tall)
Check the width/height of an element
检查元素的宽度/高度
I expect that element "([^"]*)?" is( not)* positioned at ([\d]+)px on the (x|y) axis
Check the position of an element
检查元素的位置
I expect that element "([^"]*)?" (has|does not have) the class "([^"]*)?"
Check if an element has a certain class
检查元素是否具有特定类
I expect a new (window|tab) has( not)* been opened
Check if a new window/tab has been opened
检查是否已打开新窗口/选项卡
I expect the url "([^"]*)?" is opened in a new (tab|window)
Check if a URL is opened in a new browser window/tab
检查 URL 是否在新的浏览器窗口/选项卡中打开
I expect that element "([^"]*)?" is( not)* focused
Check if an element has the focus
检查元素是否具有焦点
I wait on element "([^"]*)?"( for (\d+)ms)*( to( not)* (be checked|be enabled|be selected|be visible|contain a text|contain a value|exist))*
Wait for an element to be checked, enabled, selected, visible, contain a certain value or text or to exist
等待元素被选中、启用、选择、可见、包含特定值或文本或存在
I expect that a (alertbox|confirmbox|prompt) is( not)* opened
Check if a modal is opened
检查是否打开了模态框
I expect that a (alertbox|confirmbox|prompt)( not)* contains the text "$text"
Check the text of a modal
检查模态框的文本
When steps 步骤
I (click|doubleclick) on the (link|button|element) "([^"]*)?"
(Double)click a link, button or element
(双击)链接、按钮或元素
I (add|set) "([^"]*)?" to the inputfield "([^"]*)?"
Add or set the content of an input field
添加或设置输入字段的内容
I clear the inputfield "([^"]*)?"
Clear an input field 清除输入字段
I drag element "([^"]*)?" to element "([^"]*)?"
Drag an element to another element
将一个元素拖动到另一个元素
I submit the form "([^"]*)?"
我提交表格“([^”]*)?
Submit a form 提交表单
I pause for (\d+)ms
我暂停了 (\d+)ms
Pause for a certain number of milliseconds
暂停一定毫秒数
I set a cookie "([^"]*)?" with the content "([^"]*)?"
Set the content of a cookie with the given name to the given string
将具有给定名称的 Cookie 的内容设置为给定的字符串
I delete the cookie "([^"]*)?"
Delete the cookie with the given name
删除具有给定名称的 Cookie
I press "([^"]*)?"
我按“([^”]*)?
Press a given key. You’ll find all supported characters here. To do that, the value has to correspond to a key from the table.
按给定的键。您可以在此处找到所有支持的角色。为此,该值必须与表中的键相对应。
I (accept|dismiss) the (alertbox|confirmbox|prompt)
Accept or dismiss a modal window
接受或关闭模式窗口
I enter "([^"]*)?" into the prompt
Enter a given text into a modal prompt
在模态提示符中输入给定文本
I scroll to element "([^"]*)?"
Scroll to a given element
滚动到给定元素
I close the last opened (window|tab)
Close the last opened browser window/tab
关闭上次打开的浏览器窗口/选项卡
I focus the last opened (window|tab)
Focus the last opened browser window/tab
聚焦上次打开的浏览器窗口/选项卡
I select the (\d+)(st|nd|rd|th) option for element "([^"]*)?"
Select an option based on it's index
根据索引选择一个选项
I select the option with the (name|value|text) "([^"]*)?" for element "([^"]*)?"
Select an option based on its name, value or visible text
根据选项的名称、值或可见文本选择选项
I move to element "([^"]*)?"( with an offset of (\d+),(\d+))
Move the mouse by an (optional) offset of the specified element
将鼠标移动指定元素的 (可选) 偏移量
I switch to the iframe "([^"]*)?"
Switch to a particular iFrame on the webpage
切换到网页上的特定 iFrame
对了 怎么执行忘记说了,cmd执行下面命令
npx wdio wdio.conf.js --spec src/features/githubLogin.feature
#src/features/githubLogin.feature替换成你要测试的那个文件