devops-web-test
v1.1.4
Published
web test for devops
Downloads
2
Readme
devops-web-test
定制流水线式执行web自动化测试的工具。
推荐的目录结构
不同插件的默认值是按照如下目录结构来设置默认值的,也是我们推荐的目录结构。
- project_path
- DevOps
- devops-app (用于DevOps执行自动化测试和输出测试产物)
- matman-app (端对端测试)
- mockstar-app (数据打桩)
- README.md
- src (项目源码)
- test (测试用例)
- package.json
- DevOps
接口文档
start(dwtPath, config)
启动自动化测试。
dwtPath
,String
,DWT
(DevOps for Web Test) 目录,流水线式执行web自动化测试和输出测试产物的路径,如果插件传入了相对路径,则是相对于该路径而言config
,Object
,配置参数config.workspacePath
,String
,工作区间的路径,即项目的根目录,如果是 git 项目,则是 git 仓库的根目录config.outputPath
,String
,测试产物输出目录,默认为path.join(dwtPath, 'output')
config.plugins
,Array
,插件列表,启动测试之后,会依次执行插件的生命周期事件(init
- >beforeRun
- >run
- >afterRun
)
BasePlugin
插件的基础类,所有的插件需要继承它。启动测试之后,会依次执行插件的生命周期事件(init
- > beforeRun
- > run
- > afterRun
)。
constructor(name, opts)
name
,String
,插件的名字opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当其为函数时,会传入参数testRecorder
async init(testRecord)
初始化插件
async beforeRun(testRecord)
运行自动化测试之前执行
async run(testRecord)
运行自动化测试
async afterRun(testRecord)
运行自动化测试之后执行
shouldRun(testRecord)
判断是否应该运行该插件
PluginProject
工程项目插件,即我们原始的工程,自动化测试时,我们可能需要安装依赖和构建等操作。
constructor(name, opts)
name
,String
,插件的名字,默认值为pluginProject
opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当为函数时,接受testRecord
参数opts.rootPath
,String
,项目根路径,默认值:由于我们推荐DWT
路径为DevOps/devops-app
,因此默认值为path.join(dwtPath, '../../')
opts.usePort
,Boolean
,是否需要端口,有些开发场景时,启动项目会使用一个端口,例如 webpack 构建项目时使用热更新模式下,就需要一个端口,默认值:false
opts.port
,Number
,端口号,如果设置了opts.usePort
为true
,若没有传入,则会自动找到未被占用的端口opts.installCmd
,String|Function
,安装依赖时执行的命令,当其为函数时,会传入参数testRecorder
,默认值为function (testRecord) { return 'npm install'; }
opts.buildCmd
,String|Function
,构建项目时执行的命令,当其为函数时,会传入参数testRecorder
和port
,默认值为function (testRecord, port) { return 'npm start'; }
opts.buildCompleteCheck
,Function
,检查构建是否完成,会传入参数data
,代表的时控制台输出,在某些场景下,可以通过判断某些输出,来判断构建已经结束,如果返回true
,则将强制结束构建,默认值为function (data) { return false; }
async init(testRecord)
初始化插件,需要处理的事情包括:
- 将
rootPath
修改为绝对路径
async beforeRun(testRecord)
运行自动化测试之前执行,需要处理的事情包括:
await this.clean(testRecord);
async run(testRecord)
运行自动化测试,需要处理的事情包括:
// 进入项目中安装依赖
await this.install(testRecord);
// 获取 project 的端口号
await this.findPort(testRecord);
// 构建项目
await this.build(testRecord);
async afterRun(testRecord)
运行自动化测试之后执行,需要处理的事情包括:
await this.clean(testRecord);
async install(testRecord)
安装依赖,执行 this.installCmd
命令
async build(testRecord)
构建项目,执行 this.buildCmd
命令
async clean(testRecord)
清理,需要处理的事情包括:
- 清理端口号
port
,避免该端口号被占用
async findPort(testRecord)
获得可用的端口号,并存储在 this.port
中
PluginUnitTest
单元测试项目插件。
constructor(name, opts)
name
,String
,插件的名字,默认值为pluginUnitTest
opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当为函数时,接受testRecord
参数opts.runTestPath
,String
,执行单元测试的根路径,默认值:由于我们推荐DWT
路径为DevOps/devops-app
,因此默认值为path.join(dwtPath, '../../')
opts.outputPath
,String
,单元测试结果输出的路径,默认值:path.join(testRecord.outputPath, 'unit_test_report')
opts.coverageOutputPath
,String
,单元测试的覆盖率输出的路径,推荐放在单元测试结果输出文件夹内,默认值:path.join(this.outputPath, 'coverage')
opts.testCmd
,String|Function
,执行测试的命令,当其为函数时,会传入参数testRecorder
,默认值为function (testRecord) { return 'npm test'; }
opts.coverageCmd
,String|Function
,执行测试的命令,当其为函数时,会传入参数testRecorder
和testCmdToExecute
(实际执行的测试的命令),默认值为function (testRecord, testCmdToExecute) { return 'npm run coverage'; }
opts.onBeforeTest
,Function
,在运行测试之前执行的钩子函数,会传入参数testRecorder
和util
opts.testCompleteCheck
,Function
,检查测试过程是否完成,会传入参数data
,代表的时控制台输出,在某些场景下,可以通过判断某些输出,来判断构建已经结束,如果返回true
,则将强制结束构建,默认值为function (data) { return false; }
opts.coverageCompleteCheck
,Function
,检查覆盖率是否完成,会传入参数testRecorder
,由于生成覆盖率文件是异步的,某些时候需要实际去检查所需要的覆盖率文件是否实际已经完成,此时可以用该方法
async init(testRecord)
初始化插件,需要处理的事情包括:
- 将
runTestPath
修改为绝对路径 - 将
outputPath
修改为绝对路径 - 将
coverageOutputPath
修改为绝对路径
async beforeRun(testRecord)
运行自动化测试之前执行,暂无。
async run(testRecord)
运行自动化测试,需要处理的事情包括:
// 在运行测试之前执行的钩子函数
if (typeof this.onBeforeTest === 'function') {
await Promise.resolve(this.onBeforeTest.call(this, testRecord, util));
}
// 启动测试
await this.runTest(testRecord);
// 获取单元测试覆盖率
await this.runCoverage(testRecord);
async afterRun(testRecord)
运行自动化测试之后执行,暂无。
async runTest(testRecord)
启动测试,执行 this.testCmd
命令
async runCoverage(testRecord)
构建项目,执行 this.coverageCmd
命令
PluginMockstar
mockstar 项目插件。
constructor(name, opts)
name
,String
,插件的名字,默认值为pluginMockstar
opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当为函数时,接受testRecord
参数opts.rootPath
,String
,项目根路径,默认值:由于我们推荐DWT
路径为DevOps/devops-app
,因此默认值为path.join(dwtPath, '../mockstar-app')
opts.port
,Number
, mockstar 启动端口opts.installCmd
,String|Function
,安装依赖时执行的命令,当其为函数时,会传入参数testRecorder
,默认值为function (testRecord) { return 'npm install'; }
opts.startCmd
,String|Function
,安装依赖时执行的命令,当其为函数时,会传入参数testRecorder
和port
,默认值为function (testRecord, port) { return 'npm install'; }
async init(testRecord)
初始化插件,需要处理的事情包括:
- 将
rootPath
修改为绝对路径 - 自动生成唯一标识
this._processKey
async beforeRun(testRecord)
运行自动化测试之前执行:
await this.clean(testRecord);
async run(testRecord)
运行自动化测试,需要处理的事情包括:
// 进入项目中安装依赖
await this.install(testRecord);
// 获取 mockstar 的端口号
await this.findPort(testRecord);
// 启动 mockstar
await this.start(testRecord);
async afterRun(testRecord)
运行自动化测试之后执行:
await this.clean(testRecord);
async clean(testRecord)
清理,需要处理的事情包括:
- 清理端口号
port
,避免该端口号被占用
async findPort(testRecord)
获得可用的端口号,并存储在 this.port
中
async install(testRecord)
安装依赖,执行 this.installCmd
命令
async start(testRecord)
构建项目,执行 this.startCmd
命令
PluginWhistle
mockstar 项目插件。
constructor(name, opts)
name
,String
,插件的名字,默认值为pluginWhistle
opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当为函数时,接受testRecord
参数opts.port
,Number
, whistle 启动端口opts.getWhistleRules
,Function
,获得 whistle 规则,需要返回格式为{name: String, rules: String}
opts.configFileName
,String
,whistle 规则配置文件名,文件中包含了规则信息等,默认值为test.whistle.js
opts.configFile
,String
,whistle 规则配置文件路径,默认值为path.join(testRecord.outputPath, this.configFileName)
async init(testRecord)
初始化插件,需要处理的事情包括:
- 将
configFile
修改为绝对路径 - 自动生成唯一标识
this._processKey
async beforeRun(testRecord)
运行自动化测试之前执行:
await this.clean(testRecord);
async run(testRecord)
运行自动化测试,需要处理的事情包括:
// 获取 whistle 的端口号
await this.findPort(testRecord);
// 生成 .whistle.js 配置文件
await this.generateConfigFile(testRecord);
// 启动 whislte
await this.start(testRecord);
// 设置并强制使用指定 whistle 配置规则
await this.use(testRecord);
async afterRun(testRecord)
运行自动化测试之后执行:
await this.clean(testRecord);
async generateConfigFile(testRecord)
根据 this.getWhistleRules
获得的代理规则,生成一个本地的 whistle 配置文件。
async clean(testRecord)
清理,需要处理的事情包括:
- 清理端口号
port
,避免该端口号被占用
async findPort(testRecord)
获得可用的端口号,并存储在 this.port
中
async start(testRecord)
启动 whistle,启动命令格式为 w2 start -S ${this._processKey} -p ${this.port}
。
async use(testRecord)
使用指定的 whistle 规则配置文件,启动命令格式为 w2 use ${this.configFile} -S ${this._processKey} --force
。
PluginE2ETest
端对端测试项目插件。
constructor(name, opts)
name
,String
,插件的名字,默认值为pluginE2ETest
opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当为函数时,接受testRecord
参数opts.runTestPath
,String
,执行端对端测试的根路径,默认值:由于我们推荐DWT
路径为DevOps/devops-app
,因此默认值为path.join(dwtPath, '../../')
opts.outputPath
,String
,单元测试结果输出的路径,默认值:path.join(testRecord.outputPath, 'e2e_test_report')
opts.coverageOutputPath
,String
,单元测试的覆盖率输出的路径,推荐放在单元测试结果输出文件夹内,默认值:path.join(this.outputPath, 'coverage')
opts.testCmd
,String|Function
,执行测试的命令,当其为函数时,会传入参数testRecorder
和whistlePort
,默认值为function (testRecord, whistlePort) { return 'npm test'; }
opts.onBeforeTest
,Function
,在运行测试之前执行的钩子函数,会传入参数testRecorder
和util
opts.testCompleteCheck
,Function
,检查测试过程是否完成,会传入参数data
,代表的时控制台输出,在某些场景下,可以通过判断某些输出,来判断构建已经结束,如果返回true
,则将强制结束构建,默认值为function (data) { return false; }
opts.getWhistlePort
,Function
,获得whistle
的端口号,默认值为function (testRecord) { return 0; }
opts.matmanAppPath
,String
,matman 应用的根路径,默认值:由于我们推荐DWT
路径为DevOps/devops-app
,因此默认值为path.join(dwtPath, '../matman')
opts.matmanAppInstallCmd
,String|Function
,matman 应用安装依赖时执行的命令,当其为函数时,会传入参数testRecorder
,默认值为function (testRecord) { return 'npm install'; }
opts.matmanAppBuildCmd
,String|Function
,matman 应用构建项目时执行的命令,当其为函数时,会传入参数testRecorder
,默认值为function (testRecord,) { return 'npm run build'; }
async init(testRecord)
初始化插件,需要处理的事情包括:
- 将
runTestPath
修改为绝对路径 - 将
matmanAppPath
修改为绝对路径 - 将
outputPath
修改为绝对路径 - 将
coverageOutputPath
修改为绝对路径
async beforeRun(testRecord)
运行自动化测试之前执行,暂无。
async run(testRecord)
运行自动化测试,需要处理的事情包括:
// matman-app 安装依赖
await this.matmanAppInstall(testRecord);
// 测试之前需要 matman-app 构建
await this.matmanAppBuild(testRecord);
// 启用 xvfb
await this.startXvfb(testRecord);
// 在运行测试之前执行的钩子函数
if (typeof this.onBeforeTest === 'function') {
await Promise.resolve(this.onBeforeTest.call(this, testRecord, runCmd));
}
// 启动测试
await this.runTest(testRecord);
// 停止 xvfb
await this.stopXvfb(testRecord);
// 处理测试覆盖率
await this.createE2ECoverage(testRecord);
// copy build to output
await this.copyBuildOutputToArchive(testRecord);
async afterRun(testRecord)
运行自动化测试之后执行,暂无。
async startXvfb(testRecord)
启动 xvfb,注意只有在 process.env.USE_XVFB
存在时才会处理
async stopXvfb(testRecord)
关闭 xvfb,注意只有在 process.env.USE_XVFB
存在时才会处理
async matmanAppInstall(testRecord)
启动 matman-app 的安装依赖,执行 this.matmanAppInstallCmd
命令
async matmanAppBuild(testRecord)
启动 matman-app 的构建,执行 this.matmanAppBuildCmd
命令
async runTest(testRecord)
启动测试,执行 this.testCmd
命令
async createE2ECoverage(testRecord)
分析并生成测试覆盖率数据
async copyBuildOutputToArchive(testRecord)
将端对端测试运行结果拷贝到归档目录中
PluginArchive
归档项目插件。
constructor(name, opts)
name
,String
,插件的名字,默认值为pluginArchive
opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当为函数时,接受testRecord
参数opts.getPlugins
,Function
,获取插件,接受testRecord
参数, 返回{ pluginE2ETest: PluginE2ETest, pluginUnitTest: PluginUnitTest, pluginWhistle: PluginWhistle}
其他的属性:
this.rootPath
,String
,归档文件夹路径,值为testRecord.outputPath
this.outputZipPath
,String
,归档文件夹路径,值为path.join(this.rootPath, 'output.zip')
this.indexHtmlPath
,String
,归档文件夹路径,值为path.join(this.rootPath, 'index.html')
this.indexHtmlDataPath
,String
,归档文件夹路径,值为path.join(this.rootPath, 'index-html.json')
this.testRecordPath
,String
,归档文件夹路径,值为path.join(this.rootPath, 'test-record.json')
async init(testRecord)
初始化插件,需要处理的事情包括:
- 将
rootPath
修改为绝对路径 - 将
outputZipPath
修改为绝对路径 - 将
indexHtmlPath
修改为绝对路径 - 将
indexHtmlDataPath
修改为绝对路径 - 将
testRecordPath
修改为绝对路径
async beforeRun(testRecord)
运行自动化测试之前执行:
await this.clean(testRecord);
async run(testRecord)
运行自动化测试,需要处理的事情包括:
// 保存自定义报告入口文件
this.saveOutputIndexHtml(testRecord, pluginMap);
// 保存 testRecord 内容
this.saveTestRecordContent(testRecord);
// 压缩下 output 目录
await this.compressDir(testRecord);
async afterRun(testRecord)
运行自动化测试之后执行:
await this.clean(testRecord);
async clean(testRecord)
清理,需要处理的事情包括:
- 删除上次缓存的文件内容,即清空
this.rootPath
目录
getE2ETestReport(testRecord, pluginE2ETest)
获得端对端测试报告
getUnitTestReport(testRecord, pluginUnitTest)
获得单元测试报告
saveOutputIndexHtml(testRecord, pluginMap)
保存自定义报告入口文件
async saveTestRecordContent(testRecord)
保存 testRecord 内容
async compressDir(testRecord)
压缩保存测试输出文件
PluginCustom
自定义插件。
constructor(name, opts)
name
,String
,插件的名字,默认值为pluginCustom
opts
,Object
,插件的配置,不同插件可能有不同的区别opts.shouldSkip
,Boolean|Function
,是否应该跳过执行,当为函数时,接受testRecord
参数opts.onInit
,Function
,init
方法中的钩子函数,接受testRecord
参数opts.onBeforeRun
,Function
,beforeRun
方法中的钩子函数,接受testRecord
参数opts.onRun
,Function
,run
方法中的钩子函数,接受testRecord
参数opts.onAfterRun
,Function
,afterRun
方法中的钩子函数,接受testRecord
参数
async init(testRecord)
初始化插件,调用 this.onInit
async beforeRun(testRecord)
运行自动化测试之前执行,调用 this.onBeforeRun
async run(testRecord)
运行自动化测试,调用 this.onRun
async afterRun(testRecord)
运行自动化测试之后执行,调用 this.onAfterRun