1 | /** |
1 | /** |
1 | package com.shadow.search.biz.impl |
有问题的测试代码:
1 | package foo.bar.test |
问题原因:where块
在given
之前运行块
解决问题后的代码:
1 | package foo.bar.test |
1 | package com.shadow.cloud.dennis.chain.biz.extension.member.changyi; |
1 | package com.shadow.cloud.dennis.chain.biz.extension; |
1 | package com.shadow.cloud.dennis.chain.test |
1 |
|
通过过程监控、结果度量(包括用例维度、缺陷维度、需求维度、接口自动化维度等)等度量数据的获取,通过对于这些度量数据的分析,获取其中的异常数据,从而促进产研流程改进。
Xmind原始文件地址
1. 等价类划分法2. 边界值法3. 错误推测法4. 因果图法5. 场景法/流程分析法6. 判定表法7. 正交试验法8. 功能图法
]]>1. 管理者能够根据测试计划做宏观调控,进行相应资源配置等2. 测试负责人可以根据测试计划跟踪测试进度3. 测试人员能够了解整个项目测试情况,以及项目测试不同阶段所要进行的工作4. 便于其他人员了解测试人员的工作内容,进行有关的配合工作
]]>软件需求是测试需求的基础。软件需求分为业务需求、用户需求、功能需求3个层次。
需求包括功能需求和非功能需求两个方面。
测试需求是解决“测什么”的问题,是整个测试项目的基础,是制订测试计划、开发测试用例的依据。清晰完整的测试需求有助于保证测试的质量与进度,有助于确保测试的覆盖率。如果没有明确的测试需求就开展测试工作,那么经常会出现需求遗漏、产品质量关注不全面等问题。
测试需求分析的目标是明确测试范围和功能处理过程。
测试类型 | 测试内容描述 |
---|---|
功能测试 | 是对产品的各功能进行验证,根据功能需求逐项测试,检查产品是否达到用户要求的功能 |
兼容性测试 | 测试软件在特定的硬件平台上、不同的应用软件之间、不同的操作系统平台上、不同的网络等环境中是否能够正常运行 |
安全性测试 | 针对的是未授权的访问、拒绝访问攻击等,一般包括程序、网络、数据库的安全性测试 |
接口测试 | 是对测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是检查数据的交换、传递和控制管理过程,以及系统间的相互逻辑依赖关系等 |
数据库完整性测试 | 该项测试内容主要以数据库表为单位,检查数据库表及表中各字段命名是否符合命名规范,表中字段是否完整,数据库表中的字段描述是否正确地包括字段的类型、长度,是否为空,数据库表中的关系、索引、主键、约束是否正确 |
用户界面测试 | 即UI测试,测试用户界面功能模块的布局是否合理,整体风格是否一致,各个控件的放置位置是否符合客户使用习惯,操作是否便捷,导航是否简单易懂,界面文字是否正确,命名是否统一,页面是否美观,文字、图片组合是否合适等。除此之外,还要确保 UI功能内部的对象符合预期要求,并遵循公司或行业的标准 |
负载测试 | 负载测试通过改变系统负载方式增加负载等来发现系统中所存在的性能问题。负载测试更多的是一种测试方法,而不是测试类型,可以为性能测试、压力测试所采用。负载测试的加载方式也有很多种,可以根据测试需要来选择 |
性能测试 | 性能测试是为获取或验证系统性能指标而进行的测试。多数情况下,性能测试会在不同的负载情况下进行。性能指标主要有系统吞吐量、响应速度、CPU占用率、内存占用率等 |
压力测试 | 压力测试通常在高负载的情况下来对系统的稳定性进行测试,能更有效地发现系统稳定性的隐患及系统在负载峰值下的功能隐患等 |
疲劳强度测试 | 通过长时间运行系统,测试系统的性能,发现性能问题。测试系统的日常业务(正常情况)和高峰业务(最大业务量)长时间运行的结果 |
恢复性测试 | 测试一个系统从灾难或出错中能否很好地恢复,如系统崩溃、硬件损坏或其他灾难性出错。恢复性测试一般通过人为的各种强制性手段让软件或硬件出现故障,然后检测系统是否能正确恢复(自动恢复和人工恢复) |
配置测试 | 一般是针对硬件配置的测试,测试软件在最低配置和推荐配置情况下是否能够正常运行 |
安装卸载测试 | 确保软件在正常情况和异常情况下都能正确地完成安装和卸载。例如,进行首次安装、升级,或进行完整的或自定义的安装 |
用户文档测试 | 软件文档是软件的一部分,要确保文档能够给用户提供正确的说明或指引,重点关注文档的正确性、完备性及可理解性。交给用户的文档主要有系统帮助、用户使用手册、用户安装手册、示例及模板、图像和声音帮助、用户许可协议等 |
可用性(易用性)测试 | 让一群具有代表性的用户对产品进行典型操作,同时观察员和开发人员在一旁观察,聆听,做记录。可用性有5 个指标,分别是易学性、易记性、容错性、交互效率和用户满意度 |
稳定性(可靠性)测试 | 稳定性测试通过给系统加载一定的业务压力,让系统持续运行一段时间(一般为7x24h),检测系统是否能够稳定运行 |
内存泄漏测试 | 内存泄漏是指用动态存储分配函数动态开辟的空间,在使用完毕后未释放,导致一直占据该内存单元,直到程序结束。内存泄漏测试就是测试有没有内存空间使用完毕之后未回收的情况,一般使用专门的检测工具 |
本地化测试 | 也称为国际化测试,有些产品为了满足特定区域用户的需要,有多个语言版本,比如简体中文、繁体中文、英文、日文等。本地化测试针对特定目标区域性或区域设置的产品进行测试,在本地化的软硬件环境下测试界面、安装、卸载等内容,也要关注产品目标地区的文化、 宗教、喜好等适用性测试 |
移动APP软件测试类型 | 测试涉及的内容简介 |
---|---|
安全测试 | 软件授权注册 软件获取系统的权限,比如访问联系人信息等 |
用户界面测试 | 测试用户界面,包括导航、布局、文字、图片、配色等 |
功能测试 | 对需求文档中的功能进行测试 |
性能测试-响应速度测试 | 正常环境下,APP中的关键操作响应时间能否满足用户要求,比如安装、升级、卸载响应时间,APP启动时间,其他关键操作响应时间(搜索、上传、下载等) |
性能测试-极限测试 | 在极限条件下APP的响应速度测试,比如电量低、存储空间紧张、网速慢等运行环境比较差的情况 |
性能测试-资源占用率测试 | 典型场景下系统资源(CPU、内存)的使用情况,如 APP启动后,APP加载数据后(打开一个文件或显示了一些数据), APP长时间反复操作后 |
兼容性测试 | 不同操作系统的兼容性 不同手机分辨率的兼容性 不同手机品牌的兼容性 |
交叉事件测试 | APP在运行过程中,另外一个事件或操作发生时的测试,比如有来电、收发邮件等 |
安装卸载测试 | 在主流的系统和不同手机品牌上开展测试,包括 APP 安装、升级更新、卸载 |
质量特性 | 质量特性说明 | 子特性 | 对应的测试类型 |
---|---|---|---|
功能性 | 与一组功能及其指定的性质有关的一组属性。这里的工鞥指满足明确或隐含需求的功能 | 适合性 | 功能测试 |
准确性 | 功能测试、负载测试、压力测试、疲劳强度测试 | ||
互操作性 | 接口测试 | ||
保密安全性 | 安全性测试 | ||
功能型依从性 | 功能测试 | ||
可靠性 | 在规定的一段时间和条件下,与软件维持其性能水平的能力有关的一组属性 | 成熟性 | 功能测试、疲劳强度测试、稳定性测试 |
容错性 | 安全性测试、接口测试、完整性测试、疲劳强度测试 | ||
易恢复性 | 恢复性测试 | ||
可靠性依从性 | |||
易用性 | 与一组规定或潜在的用户为使用软件所需做的努力和对这样的使用所做的评价有关的一组属性 | 易理解性 | 用户界面测试 |
易学习性 | 用户界面测试、用户文档测试 | ||
易操作性 | 用户界面测试 | ||
吸引性 | 用户界面测试 | ||
易用性依从性 | |||
效率 | 与在规定条件下软件的性能水平和所用资源量之间的关系有关的一组属性 | 时间特性 | 负载测试、压力测试、性能测试 |
资源利用特性 | 负载测试、压力测试、性能测试、内存泄漏测试 | ||
效率依从性 | |||
可维护性 | 与进行指定的修改所需的努力有关的一组属性 | 易分析性 | |
易改变性 | |||
稳定性 | |||
易测试性 | 功能测试 | ||
维护性依从性 | |||
移植性 | 与软件可以从某一环境转移到另一环境的能力有关的一组属性 | 适应性 | 配置测试 |
易安裝性 | 安装测试 | ||
共存性 | 兼容性测试 | ||
易替换性 | 兼容性测试 | ||
可移植性的依从性 |
软件需求完成后,需要进行需求的评审,此时测试人员可以参与需求的评审。当需求确定后,测试人员可以开始进行系统测试方案及计划的制订。
软件项目总体设计方案完成后,测试人员可以开始进行集成测试方案及计划的制订。
详细设计完成后,测试方可以开始进行模块测试方案及计划的制订。
单元测试和编码一般是同步的,由开发人员自己完成。
整个模块开发完成后,测试人员开始进行模块测试。当然在这之前,所有的模块测试用例已经准备完毕。
模块测试后是集成测试和系统测试。
软件运行维护期间则要对运行期间发现的问题进行回归测试。
项目研发中的开发活动是从需求分析到概要设计,之后到详细设计,再到编码,然后是测试活动。在这个模型中,把测试作为编码之后的最后一个活动,需求分析等前期产生的错误直到后期的验收测试才能发现。测试活动在编码之后,并且只对代码测试,未能体现尽早测试的原则。虽然该模型有局限性,但是该模型仍然是指导测试开展的一个重要模型。
测试活动对应开发的4个阶段,分别是单元测试、集成测试、系统测试和验收测试。
文档名 | 作用 | 主要内容 |
---|---|---|
测试计划(测试方案) | 描述为完成软件特性的测试而采用的测试方法的细节 描述测试活动的安排和管理 | - 测试范围和策略:包括被测对象、应测试的特性不被测试的特性、测试模型、测试需求、测试设计 - 测试环境和工具 - 测试出入口准则及暂停标准 - 测试人员要求 - 测试管理约定 - 任务安排和进度计划 - 风险和应急 |
测试用例 | 描述测试用例的具体细节 | - 测试项目 - 用例编号 - 用例级别:测试用例的重要程度 - 用例可用性 - 输入值 - 预期输出 - 实测结果 - 特殊环境需求(可选) - 特殊测试步骤(可选) |
测试缺陷 | 描述测试缺陷 | - 缺陷简述 - 缺陷描述 - 缺陷级别 - 缺陷状态 |
测试报告 | 描述测试结果 | - 测试时间、地点、人员 - 测试环境 - 测试结果统计分析 - 测试评估 - 测试总计和改进 - 遗留缺陷列表 |
度量项 | 含义 | 目标和意义 |
---|---|---|
测试生产率 | 单位时间所测试的代码量/单位时间执行测试用例的数量 | 一个团队的测试能力 |
工作量变化率 | 实际花费工作量相对于估计工作量的偏差百分比 | 提高估计能力、避免过载分配任务 |
测试进度变化率 | 项目实际测试进度相对于计划进度的偏差百分比 | 监控项目以便适时采取纠偏措施 |
工作量 | 测试所做的工作小时数 | 测试为整个项目贡献的工作量 |
缺陷密度 | 千行代码发现的缺陷数/千条用例发现的缺陷数 | 用于度量被测试系统的可靠性 |
测试问题的严重性 | 测试发现问题的严重性分布 | 用于确定目前被测试系统的可靠性 |
测试用例的问题发现效率 | 测试用例发现问题的数量 | 用于度量测试用例的有效性 |
测试用例覆盖率 | 需求覆盖率、功能点覆盖率、代码覆盖率等 | 度量测试的充分性 |
问题遗漏率 | 发布后反馈问题数/产品问题总数量 | 衡量内部测试质量 |
Chrome浏览器,超链接点击后,在新的标签页打开,且切换到新的标签页
快捷键:COMMAND + SHIFT + 鼠标左键点击超链接
适用场景:不想页面跳转,又想立马看到超链接页面的内容
Chrome浏览器,超链接点击后,在新的窗口打开,且切换到新的窗口
快捷键:SHIFT + 鼠标左键点击超链接
适用场景:已经打开多个标签了,再在同一窗口打开标签会造成切换标签不便时
Chrome浏览器,超链接点击后,在新的标签页打开,且停留在当前标签页
快捷键:COMMAND + 鼠标左键点击超链接
适用场景:需要快速查看单页面内的多个内部跳转的页面,又不想要每次查看再返回
请求头管理插件ModHeader
插件下载地址:https://bewisse.com/modheader/
浏览器代理切换工具SwitchyOmega
插件下载地址:https://github.com/FelisCatus/SwitchyOmega/releases
Web开发者助手FeHelper
插件下载地址:https://www.baidufe.com/fehelper/index/index.html
插件常用功能列表:
浏览器黑暗模式DACK READER
插件下载地址:https://darkreader.org/
网页翻译工具彩云小译
插件下载地址:https://fanyi.caiyunapp.com/#/web
整篇文章,根据段落进行翻译,中文在英文下展示,即直观有方便
网页json格式化工具JSON Formatter
插件下载地址:https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa
浏览器请求返回的JSON结果,会自动格式化后进行可视化展示
问题可能原因:因为系统升级原因,/Library/Application\ Support/com.apple.TCC
目录中的文件,损坏或权限异常
导致在系统偏好设置-安全性与隐私-隐私-屏幕录制
中,无法添加软件,从而无法进行截图和录屏。
解决方案:删除/Library/Application\ Support/com.apple.TCC
目录中的TCC.db
文件,然后重启系统
然后重新在系统偏好设置-安全性与隐私-隐私-屏幕录制
中添加软件,就可以看到对应软件被添加到了列表中
接口名:https://jira.shadow.com/rest/api/2/issue/{issueIdOrKey}
Returns a full representation of the issue for the given issue key.
An issue JSON consists of the issue key, a collection of fields, a link to the workflow transition sub-resource, and (optionally) the HTML rendered values of any fields that support it (e.g. if wiki syntax is enabled for the description or comments).
The fields param (which can be specified multiple times) gives a comma-separated list of fields to include in the response. This can be used to retrieve a subset of fields. A particular field can be excluded by prefixing it with a minus.
By default, all (all) fields are returned in this get-issue resource. Note: the default is different when doing a jql search – the default there is just navigable fields (navigable).
The {@code properties} param is similar to {@code fields} and specifies a comma-separated list of issue properties to include. Unlike {@code fields}, properties are not included by default. To include them all send {@code ?properties=*all}. You can also include only specified properties or exclude some properties with a minus (-) sign.
JIRA will attempt to identify the issue by the issueIdOrKey path parameter. This can be an issue id, or an issue key. If the issue cannot be found via an exact match, JIRA will also look for the issue in a case-insensitive way, or by looking to see if the issue was moved. In either of these cases, the request will proceed as normal (a 302 or other redirect will not be returned). The issue key contained in the response will indicate the current value of issue’s key.
The expand param is used to include, hidden by default, parts of response. This can be used to include:
Parameter | Value | Type | Style | Description |
---|---|---|---|---|
issueIdOrKey* | string | template | the issue id or key to update (i.e. JRA-1330) | |
fields | string | query | the list of fields to return for the issue. By default, all fields are returned. | |
expand | string | query | ||
properties | string | query | the list of properties to return for the issue. By default no properties are returned. | |
updateHistory | boolean | query |
主要说明expand
字段
changelog
时,对应这个接口获取到的数据为JIRA
的Issue详情页
的活动日志-改动记录
1 | { |
示例:project = CARSERVICE AND issuetype = 缺陷 AND priority in (P0, P1) AND createdDate >= "2020-11-20 01:00" AND createdDate <= "2020-11-20 11:08" ORDER BY created DESC
用于时间段精确搜索的字段key
叫createDate
(创建时间精确搜索),用于更新时间精确搜索的字段key
叫updatedDate
。
其中createDate
或者updatedDate
,正确的日期格式是:yyyy/MM/dd HH:mm
,yyyy-MM-dd HH:mm
,yyyy/MM/dd
,yyyy-MM-dd
,或者是一个时间段-5d
,4w 2d
。
接口名:https://jira.shadow.com/rest/api/2/issue/{issueIdOrKey}/comment
Returns all comments for an issue.
Results can be ordered by the “created” field which means the date a comment was added.
Parameter | Value | Type | Style | Description |
---|---|---|---|---|
issueIdOrKey* | string | template | to get comments for | |
startAt | long | query | the page offset, if not specified then defaults to 0 | |
maxResults | int | query | how many results on the page should be included. Defaults to 50. | |
orderBy | string | query | ordering of the results. | |
expand | string | query | optional flags: renderedBody (provides body rendered in HTML) |
接口名:https://jira.shadow.com/rest/api/2/filter/{id}
Returns a filter given an id
从Response
中可以拿到筛选器对应的JQL
条件
Parameter | Value | Type | Style | Description |
---|---|---|---|---|
id* | long | template | the id of the filter being looked up | |
expand | string | query | the parameters to expand |
接口名:https://jira.shadow.com/rest/api/2/search
Searches for issues using JQL.
Sorting the jql parameter is a full JQL expression, and includes an ORDER BY clause.
The fields param (which can be specified multiple times) gives a comma-separated list of fields to include in the response. This can be used to retrieve a subset of fields. A particular field can be excluded by prefixing it with a minus.
By default, only navigable (navigable) fields are returned in this search resource. Note: the default is different in the get-issue resource – the default there all fields (all).
Expanding Issues in the Search Result: It is possible to expand the issues returned by directly specifying the expansion on the expand parameter passed in to this resources.
For instance, to expand the “changelog” for all the issues on the search result, it is neccesary to specify “changelog” as one of the values to expand.
Parameter | Value | Type | Style | Description |
---|---|---|---|---|
jql | string | query | a JQL query string | |
startAt | int | query | the index of the first issue to return (0-based) | |
maxResults | int | query | the maximum number of issues to return (defaults to 50). The maximum allowable value is dictated by the JIRA property ‘jira.search.views.default.max’. If you specify a value that is higher than this number, your search results will be truncated. | |
validateQuery | boolean | query | whether to validate the JQL query | |
fields | string | query | the list of fields to return for each issue. By default, all navigable fields are returned. | |
expand | string | query | A comma-separated list of the parameters to expand. |
接口名:https://jira.shadow.com/rest/api/2/customFields
Parameter | Value | Type | Style | Description |
---|---|---|---|---|
startAt | long | query | ||
maxResults | int | query | ||
search | string | query |
1 | { |
公司内部JIRA的API文档地址:https://jira.shadow.com/plugins/servlet/restbrowser#/
JIRA官方提供的API文档地址:https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/
官方已经出到第三个版本,使用时需要根据自己公司使用的API版本来进行调用
官方提供了各个语言的调用示例,可以进行参考
图床服务的API文档地址:https://doc.sm.ms/
如果自己公司有影像件服务的话,可以传到公司的oss上进行保存
getIssuesList()
方法获取问题列表
首先调用filter
接口,获取到筛选器的详情,从中取出jql
字段值
然后调用search
接口,获取问题列表
getShowWords()
方法获取问题列表中所需的字段,并构建新的jsonList
从原有复杂的问题列表的json返回接口中,提取出所需的字段
1 | [ |
json2Excel()
方法把第二点中得到的json转换成Excel
,返回写入内容的Excel
文件
excel2Image.py
自定义类中的excel_html()
方法把Excel
文件转换为HTML
文件
excel2Image.py
自定义类中的html_image()
方法把HTML
文件转换为.png
格式的图片
getBugImageUrl()
方法把图片上传到图床服务,并获取到对应的图片URL
sendMarkdownDing()
方法以markdown格式组织消息体,发送钉钉通知
excel2Image.py
自定义类文件1 | # -*- coding:utf-8 -*- |
jiraSearch.py
脚本实现文件1 | # -*- coding: utf-8 -*- |
Jenkins中配置Allure插件,目录为System Configuation -> Global Tool Configuration
,从中找到Allure Commandline
下载owners-failed-plugin
插件
插件地址 提取码: ifqw
把插件加入Allure Commandline
的安装目录中
安装完插件后,可以在Jenkins任务的执行机上,也就是jenkins任务真正执行的机器上,会有一个workspace/tools/ru.yandex.qatools.allure.jenkins.tools.AllureCommandlineInstallation/Allure_Commandline/plugins
目录,这个workspace
也就是Jenkins的一个工作空间plugins
目录下,就是Allure
插件自带的一些插件
我们把第二步下载的插件解压后的文件夹,放到该目录下,owners-failed-plugin
展示如下:
1 | # shadow @ domain in ~/jenkins_slave/workspace/tools/ru.yandex.qatools.allure.jenkins.tools.AllureCommandlineInstallation/Allure_Commandline/plugins [15:55:35] |
然后需要退一层目录,把插件的配置写入配置文件中,不然就无法被调用到
1 | shadow @ domain in ~/jenkins_slave/workspace/tools/ru.yandex.qatools.allure.jenkins.tools.AllureCommandlineInstallation/Allure_Commandline/plugins [15:55:51] |
编辑allure.yml文件,写入owners-failed-plugin
配置如下:
1 | plugins: |
getSummary()
方法返回总体信息
1 | { |
getResultDetails()
方法返回Owner具体信息,并对异常数据做清理
1 | [ |
getPersonCounts()
方法返回每个Owner的具体用例数据
1 | [ |
spillDingText()
方法返回钉钉发送消息体中的text
sendMarkdownDing()
方法以markdown格式组织消息体,发送钉钉通知
1 | # -*- coding: utf-8 -*- |
1 | git clone https://github.com/easy-mock/easy-mock.git |
推荐使用nvm
来管理本地Node
服务,方便随意切换Node
版本
1 | brew install nvm |
Linux下安装Brew
然后再安装指定版本的Node
1 | nvm install 10.22.0 |
安装MongoDB服务
注意文件目录需要放在当前用户有权限的位置,否则可能会有无法辨别的报错信息
基本命令如下:
1 | $ npm run dev |
服务启动后,登录主页如下:
如果IP+Port的方式无法访问,可能就是网络上的访问的限制了,可以配置一个域名映射解决
1 | # shadow @ kickseed in ~/easy-mock on git:dev x [17:43:05] C:1 |
安装curl命令:
1 | sudo apt-get install curl |
报错信息如下:
1 | # shadow @ kickseed in ~/easy-mock on git:dev x [17:53:45] |
需要安装webpack,命令如下:
1 | sudo apt-get install webpack |
1 | # shadow @ kickseed in ~/easy-mock on git:dev x [17:54:02] C:134 |
切换node版本为8.17.0
1 | nvm install 8.17.0 |
安装brew
1 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" |
安装NVM
1 | brew install nvm |
配置环境变量
在环境变量文件中加入如下内容,如zsh
即为~/.zshrc
1 | export NVM_DIR=~/.nvm |
安装指定版本的node
1 | nvm install 8.17.0 |
nvm
常用命令
1 | nvm ls-remote # 查看所有的node可用版本 |
问题解决
问题如下:
1 | nvm ls-remote |
解决方法:
1 | brew switch openssl 1.0.2s |
Xpath
命令调试查看元素是否找到,如果有返回一个列表:$x('xpath路径")][text()="项目总数"]')
示例:
1 | $x("//*[text()='确认']") |
实现元素点击:$x('xpath路径")][text()="项目总数"]')[0].click()
示例:
1 | $x("//*[text()='确认']")[0].click() |
调试模式下的其它元素定位方法
表达式 | 实例 | 描述 |
---|---|---|
/ | xpath('//div') | 路径以/ 开始,表示找到满足绝对路径的元素 |
// | xpath('//div') | 路径以// 开始,表示找到文档中所有满足// 后规则的元素,如//div 表示找到所有div 元素 |
* | xpath('/div/*') | 表示选择所有元素 |
[表达式] | xpath('/body/div[1]') xpath('/body/div[@class]') xpath('/body/div[@class="main"]') | ①[数字]:表示选择第几个,其中[last()]表示最后一个 ②[@属性]限定满足该属性,如 //TEXT[@name] 表示含有name 属性的TEXT 元素;//TEXT[not(@*)] 表示所有没有属性的TEXT 元素;③ /TEXT[@name="text"] 表示所有含有name属性且其值为text 的TEXT 元素 |
| | xpath(‘//div|//table’) | 逻辑或,将多个路径合并到一起,如//BBB | /AAA 选择所有BBB元素和根元素AAA;可合并的路径数目没有限制 |
Xpath
定位方法绝对路径定位
就是从根部开始找,一级一级往下走,如果有同级别的需要用[]标明序号,从1开始
1 | // CSDN博客的博主头像 |
相对路径定位
1 | /html/body/div[1]/div[2]/div[1]/div[1]/form/span[1]/input |
以下都以定位到input
做说明。
2.1 元素本身查找(@表示属性)
1 | //input[@id="kw"] |
//input
表示匹配input
标签的所有元素//*
表示匹配所有元素的标签
2.2 布尔值写法
如果input
标签中,id
不是唯一的,type
也不是唯一的,但在该页面中包含该id
和type
的只有这个元素时,就可以用组合的方式定位
1 | //*[@id="kw" and @type="text"] |
2.3 找父级
如果自己没有唯一的标志,那么就找自己的上级(父级),或者上级的上级,以此类推。
1 | //找父级 |
2.4 跳级
如果需要定位的元素在该页面不是唯一,但在某个容器内是唯一的,当然那个容器必须要有唯一的标志;
该方法要保证在某容器内该元素是唯一的。
1 | //div[@id="wrapper"]//input[@id="kw"] |
Xpath
函数过滤
3.1 contains()
1 | //div[contains(@id,'in')] |
表示选择id
中包含有in
的div
节点
3.2 text()
1 | //a[text()='baidu'] |
由于一个节点的文本值不属于属性,比如<a class="baidu" herf="http://www.baidu.com">baidu</a>
,所以用text()
函数来匹配节点
3.3 last()
表示取列表的最后一个
3.4 start-with()
1 | //div[starts-with(@id,'in')] |
表示选择以in
开头的id
属性的div
节点
3.5 not()
函数
1 | //input[@name='identity' and not(contains(@class, 'a'))] |
表示匹配出name
为identity
,并且class
的值中不包含a的input
节点;
not()函数通常与返回值为true or false
的函数组合使用,比如contains()
,starts-with()
等;
有一种特殊情况需要注意:要匹配出input
节点下所有的id
属性//input[@id]
,要匹配出input
节点下不含有id
属性//input[not(@id)]
轴&步
轴可定义相对于当前节点的节点集。
轴名称 | 描述 |
---|---|
ancestor | 选取当前节点的所有先辈(父、祖父等)。 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
attribute | 选取当前节点的所有属性。 |
child | 选取当前节点的所有子元素。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
following-sibling | 选取当前节点之后的所有同级节点 |
namespace | 选取当前节点的所有命名空间节点。 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
self | 选取当前节点。 |
语法:轴名称::节点测试[谓语]
实例1:
例子 | 结果 |
---|---|
child::book | 选取所有属于当前节点的子元素的 book 节点。 |
attribute::lang | 选取当前节点的 lang 属性。 |
child::* | 选取当前节点的所有子元素。 |
attribute::* | 选取当前节点的所有属性。 |
child::text() | 选取当前节点的所有文本子节点。 |
child::node() | 选取当前节点的所有子节点。 |
descendant::book | 选取当前节点的所有 book 后代。 |
ancestor::book | 选择当前节点的所有 book 先辈。 |
ancestor-or-self::book | 选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点) |
child::*/child::price | 选取当前节点的所有 price 孙节点。 |
实例2:复杂HTML列表定位
1 | <div data-v-f7a7d94e="" id="carInfo" class="mt48"> |
UI组件化获取label对应的value:
1 | //div[@class='title' and contains(text(),'"+分组名+"')]/parent::div/div[@class='content']/descendant::div[contains(@class,'label') and text()='"+标签+"']/parent::div/div[@class='value'] |
title
的名称label
的名称//div[@class='title' and contains(text(),'"+分组名+"')]
:选取div
中,class
等于title
,并且div
中文案包含对应的分组名
的节点parent::div/div[@class='content']
:选取父级div
节点的子div
节点中,class
等于content
的节点descendant::div[contains(@class,'label') and text()='"+标签+"']
:选取当前节点所有的div
子节点中,class
包含label
,并且文本等于标签
值的节点parent::div/div[@class='value']
:选取父级div
节点的子div
节点中,class
等于value
的节点实例3:Python中xpath取值
可以从需要的值开始往外取值,直到取值唯一就OK
1 | from lxml import etree |
TestNG
介绍TestNG
是一个开源自动化测试框架;TestNG
表示下一代(Next Generation的首字母)。
TestNG的特点:
TestNG
测试类配置注释说明注解 | 描述 |
---|---|
@BeforeMethod | 在每个测试方法 前 执行 |
@AfterMethod | 在每个测试方法 后 执行 |
@BeforeClass | 被注释的方法将在当前类的第一个测试方法调用前运行 |
@AfterClass | 被注释的方法将在当前类的所有测试方法调用后运行 |
@BeforeGroups | 被配置的方法将在列表中的gourp前运行。这个方法保证在第一个属于这些组的测试方法调用前立即执行 |
@BeforeTest | 被注释的方法将在测试运行前运行 |
@AfterTest | 被注释的方法将在测试运行后运行 |
@BeforeSuite | 被注释的方法将在所有测试运行前运行 |
@AfterSuite | 被注释的方法将在所有测试运行后运行 |
alwaysRun | 对于每个bufore方法(beforeSuite, beforeTest, beforeTestClass 和 beforeTestMethod, 但是不包括 beforeGroups):\n如果设置为true,被配置的方法将总是运行而不管它属于哪个组。\n对于after方法(afterSuite, afterClass, …): 如果设置为true,被配置的方法甚至在一个或多个先调用的方法失败或被忽略时也将运行。 |
dependsOnGroups | 这个方法依赖的组列表 |
dependsOnMethods | 这个方法依赖的方法列表 |
enabled | 这个类的方法是否激活 |
groups | 这个类或方法所属的分组列表 |
inheritGroups | 如果设置为true,这个方法被属于在类级别被@Test annotation指定的组 |
testng.xml
配置详解XML
规则XML
简单的大概结构1 | <suite name="xxx"> |
<suite>
说明:一个xml
文件只能有一个<suite>
,是一个xml
文件的根级<suite>
由<test>
和<parameters>
组成
参数说明:
参数 |说明|使用方法|参数值
——————————|—|—|—name
|必选项,junit
|是否执行Junit模式(识别setup()等)|junit=”true”|true和false,默认falseverbose
|控制台输出的详细内容等级,0-10级(0无,10最详细)|verbose=”5”|0到10parallel
|是否在不同的线程并行进行测试,要与thread-count配套使用|parallel=”mehods”|详见表格下内容,默认falseparent-module
|和Guice框架有关,只运行一次,创建一个parent injector给所有guice injectors|guice-stage
|和Guice框架有关|guice-stage=”DEVELOPMENT”|DEVELOPMENT,PRODUCTION,TOOL,默认”DEVELOPMENT”configfailurepolicy
|测试失败后是再次执行还是跳过,值skip和continue|configfailurepolicy=”skip”|skip、continue,默认skipthread-count
|与parallel配套使用,线程池的大小,决定并行线程数量|thread-count=”10”|整数,默认5annotations
|获取注解,值为javadoc时,使用JavaDoc的注释;否则用JDK5注释|annotations=”javadoc”|javadoctime-out
|设置parallel时,终止执行单元之前的等待时间(毫秒)|time-out=”10000”|整数,单位毫秒skipfailedinvocationcounts
|是否跳过失败的调用|skipfailedinvocationcounts=”true”|true和false,默认falsedata-provider-thread-count
|并发时data-provider的线程池数量|data-provider-thread-count=”5”|整数object-factory
|一个实现IObjectFactory接口的类,实例化测试对象|object-factory=”classname”|类名allow-return-values
|是否允许返回函数值|all-return-values=”true”|true和falsepreserve-order
|是否按照排序执行|preserve-order=”true”|true和false,默认truegroup-by-instances
|按照实例分组|group-by-instances=”true”|true和false,默认false
<test>
说明:一个<test>
由<parameters>
、<groups>
、<classes>
三部分组成
参数说明:
参数 |说明|使用方法|参数值
——————————|—|—|—name
|test的名字,将出现在报告里|name=”testname”|test的名字junit
|是否按照Junit模式运行|junit=”true”|true和false,默认falseverbose
|控制台输出的详细内容等级,0-10级(0无,10最详细),不在报告显示|verbose=”5”|0到10parallel
|是否在不同的线程并行进行测试,要与thread-count配套使用|parallel=”mehods”|与suite的parallel一致,默认falsethread-count
|与parallel配套使用,线程池的大小,决定并行线程数量|thread-count=”10”|整数,默认5annotations
|获取注解,值为javadoc时,使用JavaDoc的注释;否则用JDK5注释|annotations=”javadoc”|javadoctime-out
|设置parallel时,终止执行单元之前的等待时间(毫秒)|time-out=”10000”|整数,单位毫秒enabled
|标记是否执行这个test|enabled=”true”|true和false,默认trueskipfailedinvocationcounts
|是否跳过失败的调用|skipfailedinvocationcounts=”true”|true和false,默认falsepreserve-order
|是否按照排序执行,如果是true,将按照xml文件中的顺序去执行|preserve-order=”true”|true和false,默认trueallow-return-values
|是否允许返回函数值|all-return-values=”true”|true和false,默认false
parallel
该参数的值可以是false
、methods
、tests
、classes
、instances
。默认false
parallel
必须和thread-count
配套使用,否则相当于无效参数,thread-count
决定了并行测试时开启的线程数量
parallel="mehods"
TestNG将并行执行所有的测试方法在不同的线程里parallel="tests"
TestNG将并行执行在同一个parallel="classes"
TestNG将并行执行在相同parallel="instances"
TestNG将并行执行相同实例下的所有方法在不同的线程里<parameter>
说明:提供测试数据,有name
和value
两个参数
声明方法:<parameter name = "parameter_name" value = "parameter_value "/>
testng.xml
文件中的<parameter>
可以声明在<suite>
或者<test>
级别,在<test>
下的<parameter>
会覆盖在<suite>
下声明的同名变量
使用示例:
1 | public class TestParameterXML { |
<DataProvider>
使用示例:
1 | package com.yiibai; |
<groups>
说明:要运行的组,可以自定义一个组,可以包括要执行的,还排除要执行的方法。必须和<classes>
配套使用,从下面的类中找到对应名字的方法<groups>
由<difine>
和<run>
、<dependencies>
三部分组成。<diffine>
可以将group
组成一个新组,包括要执行和不执行的大组;<run>
要执行的方法;<dependencies>
指定了某group
需要依赖的group
(比如下面的例子,group1
需要依赖group2
和group3
先执行)。
声明方法:
1 | <groups> |
<classes>
说明:方法选择器,要执行的方法写在这里,参数有name
和priority
。
注释:
1.
2.
声明方法:
1 | <classes> |
<packages>
说明:<packages>
指定包名代替类名。查找包下的所有包含testNG annotation
的类进行测试
声明方法:
1 | <packages> |
<listener>
说明:指定listeners
,这个class
必须继承自org.testng.ITestNGListener
。在java
中使用@Listeners({com.example.MyListener.class,com.example.MyMethodInterceptor.class})
的注释也可以有同样效果
声明方法:
1 | <listeners> |
在测试用例写好,但是并没有调试或者说还没有测试通过时,希望先不要执行该测试,可以使用@Test(enabled = false)
来忽略这个测试方法。默认情况下,enabled
参数是true
。
超时
表示如果单元测试花费的时间超过指定的毫秒数,那么TestNG
将会终止它,并标记为失败。超时
也可用于性能测试,以确保方法在合理的时间内返回。
示例代码如下:
1 | package com.yiibai; |
对于TestNG
,首先重写接口IRetryAnalyzer
,重写该接口中的retry
方法,自定义需要重试的次数maxRetryCount
,如果一个用例失败,自动进入retry
方法,在此方法中判断已经重试的次数是否小于maxRetryCount
,如果是,则返回true
,则自动再次执行失败的用例,如果是失败的用例再次执行还是失败,那么还是自动调用retry
方法,直到到重试次数大于设定的maxRetryCount
了,则返回false
,那么系统就是判定该方法失败了。
失败用例重跑方法代码:
1 | package com.shadow.qa.common.listeners; |
重写了TestNG
的IRetryAnalyzer
接口,那么就需要让系统调用我们重写的接口,需要让TestNG
调用,还需要对TestNG.xml
中的注解接口进行重写。先判断TestNG.xml
中是否有重试分析器,如果没有,则调用我们自己重写类。
失败重跑监听器代码:
1 | package com.shadow.qa.common.listeners; |
使用方法一:在TestNG
的执行文件中配置
在TestNG
的执行文件的suite
标签中,增加一个监听器,用于监听suite
下所有的用例执行情况。
1 | <suite name="接口测试" verbose="1" > |
使用方法二:对特定的用例进行设置
在用例的@Test
中,增加失败用例重跑的参数
1 | "data", description = "Test", retryAnalyzer = TestNGRetryAnalyzer.class) (dataProvider = |
groups
时,@BeforeClass
、@BeforeSuite
被跳过有两种解决方式:
在@BeforeClass
中添加alwaysRun=true
1 | public class classTest { |
testNG
文件中包含了该class
中存在的groups
时,该class
中的@BeforeClass
才会执行,所以不必担心在所有的@BeforeClass
中都添加alwaysRun=true
会造成没必要的@BeforeClass
执行的问题。
在@BeforeClass
中也添加需要的groups
参数
1 | public class classTest { |
testNG的xml配置文件如下:
1 |
|
多数文档说groups
必须和classes
配合使用,但是class
是无法用通配符的,会造成要枚举所有的class
,这样就会非常麻烦;
实际上groups
也可以和packages
配合使用,packages
可以使用通配符,这样就大大省去了去找所有有需要的groups
的class
的麻烦
官网
官方入门教程
VuePC端UI组件库:Element、iView、[vue-element-admin](https://panjiachen.github.io/vue-element
-admin-site/#/)、更多
列表头增加筛选项『下拉选择、输入框』
在……中增加如下代码
1 | <el-form-item label="角色"> |
筛选字段定义
①定义筛选字段所需的自定义下来列表项
②增加两个筛选的值的字段定义
1 | <script> |
筛选接口增加筛选字段的传参
在请求接口中新增两个字段:role_id、status
1 | <script> |
通过 css属性
实现
示例1:
1 | <p style="white-space: pre-wrap;" v-text='item.des'></p> |
示例2:
1 | <el-row> |
white-space
的各属性详情可以阅读这里
通过v-html
实现
需要先把字符串里的\n
替换为<br>
,然后用v-html
指令渲染字符串为innerHTML
。
1 | // JS部分 |
包下载地址:官网下载地址
监控服务
部署下载上述的监控服务包,并解压,可以得到如下文件:
1 | root@su-007:~/tools/prometheus-2.13.1.linux-amd64# ll |
其中prometheus*
为服务启动脚本文件,prometheus.yml
为普罗米修斯监控系统的配置文件
全量配置如下:
1 | # my global config |
其中主要使用了几个模块的监控,没有会用报警,有需要的话,可以自己尝试。
几个模块的定义介绍:
- job_name: 'prometheus'
:是监控程序本身,用于监控检测被监控系统是否正确连接,默认端口9090
- job_name: "mysql"
:监控mysql服务器的情况,默认端口9104
- job_name: "node"
:监控服务器状态,默认端口9100
- job_name: 'java'
:JVM监控,这里的端口是自己在启动tomcat应用服务时,在启动脚本中自己定义的端口号
这里的job_name
都是可以自己定义,主要用来区分几个监控模块
配置好配置文件后,就可以启动监控服务了
1 | nohup ./prometheus >> ./nohup.log 2>&1 & |
启动脚本,设置后台运行,并把运行日志写进nohup.log
文件中
启动后,就可以在浏览器中访问10.10.10.10:9090/targets
查看各个节点的状态了,确保State
是UP
,不然就可能有问题,需要排查了
服务器
监控部署下载上述的服务器监控服务包,并解压,可以得到如下文件:
1 | root@su-007:~/tools/node_exporter-0.18.1.linux-amd64# ll |
这里面东西很简单,它不需要配置文件,只有一个关键的node_exporter*
启动脚本文件,直接启动脚本就OK
1 | nohup ./node_exporter >> ./nohup.log 2>&1 & |
在浏览器访问10.10.10.10:9100/metrics
,可以看到监控数据,就说明服务启动成功了
MySQL
监控部署下载上述的MySQL监控服务包,并解压,可以得到如下文件:
1 | root@test-01:~/tools/mysqld_exporter-0.12.1.linux-amd64$ ll |
默认只有一个mysqld_exporter*
启动脚本文件。mysqld_exporter
需要连接到Mysql,所以需要Mysql的权限,我们先为它创建用户并赋予所需的权限。
命令行登录mysql,执行如下命令:
1 | mysql> GRANT REPLICATION CLIENT,PROCESS ON *.* TO 'mysql_monitor'@'localhost' identified by 'mysql_monitor'; |
创建mysqld_exporter
执行的配置文件.my.cnf
,写入如下内容:
1 | [client] |
启动监控服务并调用脚本文件:
1 | nohup ./mysqld_exporter --config.my-cnf=./.my.cnf >> ./nohup.log 2>&1 & |
在浏览器访问10.10.10.11:9104/metrics
,可以看到监控数据,就说明服务启动成功了
JVM
监控部署下载上述的jar文件,创建配置文件jmx_exporter.yml
配置文件内容如下:
1 | #--- # ---前的#要去掉 |
在启动tomcat的脚本中,添加参数-javaagent:/home/shadow/tools/JMX/jmx_prometheus_javaagent-0.12.0.jar=3080:/home/shadow/tools/JMX/jmx_exporter.yml
在启动脚本中:
1 | CATALINA_OPTS="-Xms2g -Xmx2g -javaagent:/home/shadow/tools/JMX/jmx_prometheus_javaagent-0.12.0.jar=3080:/home/shadow/tools/JMX/jmx_exporter.yml" |
这里定义的3080端口,既是prometheus
监控服务获取JVM参数的端口
还有一点需要注意的是:jmx_prometheus_javaagent-0.12.0.jar
和jmx_exporter.yml
存放的位置必须和tomcat的位置在同一用户下,不然可能会出现因为权限问题,无法调用的情况。
在浏览器访问10.10.10.11:3080/metrics
,可以看到监控数据,就说明服务启动成功了
Grafana
各个监控面板配置每个不同类型的监控,需要有不同类型的面板,这里不自己配置面板,而是从外部导入,官方Dashboards平台
主机基础监控(cpu,内存,磁盘,网络)
,ID
为9276
MySQL Overview
,ID
为7362
JMX Overview
,ID
为3457
VIM编辑下,控制光标
1 | # 命令模式下,移动光标到段位 |
MAC下,命令行控制
1 | ctrl + a 移动到命令行首 |
Docker
MAC平台
Windows平台
Ubuntu平台
Centos7平台
hub
镜像selenium/hub
1 | # 安装 |
-d
表示容器以守护态(Daemonized)形式运行。-P
表示 Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。
node chrome
镜像selenium/node-chrome
1 | # 安装 |
--link
通过 link 关联selenium-hub
容器,并为其设置了别名hub
1 | $ docker ps -a |
Selenium/hub
容器的端口号为4444
,对MAC
映射的端口为32768
,前面通过-P
参数自动分配。
selenium Grid脚本 -> ubuntu(32768) -> Hub容器(4444) -> Node Chrome 容器
1 | # grid_demo.py |
1 | docker run --name=chrome -p 5902:5900 \ |
自身电脑的代理打开全局代理
设置好全局代理后,查看全局代理情况下,电脑默认设置的socks代理IP和端口
然后设置Telegram的代理Settings
-Advanced
-Network and proxy
-Connection type
Use custom proxy
,然后选择ADD PROXY
,选择SOCKS5
,填写其中的Hostname
和Port
Can't locate revision identified by '3ba21fe709f1'
问题处理1 | # taoyi @ TyMac in ~ [16:26:14] |
1 | mysql> SELECT * FROM alembic_version; |
1 | DROP TABLE alembic_version; |
migrations
文件夹,重新生成迁移版本文件夹1 | flask db init |
1 | flask db migrate |
query.filter
常见操作符1 | query.filter(User.name == 'ed') |
1 | query.filter(User.name != 'ed') |
1 | query.filter(User.name.like('%ed%')) |
1 | query.filter(User.name.in_(['ed', 'wendy', 'jack'])) |
1 | query.filter(~User.name.in_(['ed', 'wendy', 'jack'])) |
1 | query.filter(User.name == None) |
1 | query.filter(User.name != None) |
1 | # use and_() |
1 | from sqlalchemy import or_ |
1 | query.filter(User.name.match('wendy')) |
1 |
|