Nodemailer

团队需要我做一个解析测试报告的程序,将最终结果发邮件给所有相关同事,前期自动化测试都是基于jenkins+gitlab+newman,发送邮件使用的是jenkins配置邮件插件。
这次需要借助非jenkins发送邮件,找了很久Nodemailer比较适合。

1
npm i nodemailer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
var nodemailer = require("nodemailer");
// var smtpTransport = require('nodemailer-smtp-transport');

describe('', () => {
it.skip('发送邮件', function () {

var transport = nodemailer.createTransport({
host: "smtp.qq.com",// SMTP 端口
secureConnection: true,// 使用 SSL
port: 465,
auth: {
user: "liyinchi@qq.com",//邮箱账号
//这里密码不是qq密码,是你设置的smtp密码
pass: ""//授权码
}
});

var mailOptions = {
from: "liyinchi@qq.com",// 发件地址
to: "yinchi.li@xxxx.com",// 收件列表
// Subject of the message 邮件主题
subject: 'Nodemailer is unicode friendly ✔' + Date.now(),// 标题
//text和html两者只支持一种
// 标题
text: 'Hello to myself!',
// html 内容
html: `<p><b>Hello</b> to myself <img src="cid:note@example.com"/></p>
<p>Here's a nyan cat for you as an embedded attachment:<br/><img src="https://www.baidu.com/s?rsv_idx=1&wd=foreach&ie=utf-8&rsv_cq=js+%E6%88%AA%E5%8F%96%E6%95%B0%E7%BB%84&rsv_dl=0_right_recommends_merge_28335&euri=262673"/></p>`,
// An array of attachments
attachments: [
// String attachment 文本附件
{
filename: 'notes.txt', //附件名称,文本格式
content: '这是在notes.txt的内容', //文本中的内容
contentType: 'text/plain' // 可选,将从文件名中检测到
},
// File Stream attachment
{
filename: 'cat.jpg',
path: '/Users/liyinchi/workspace/前端/vue/test-file-management-platform/back-end/assets/nyan.jpg',
}
],
}

transport.sendMail(mailOptions, function (err, info,response) {
if (err) {
console.log(err);
console.log(info.accepted);
} else {
console.log(response);
}
})
})


});

测试工作管理平台

为了更好的管理团队测试工作,项目测试环节风险把控、测试工作饱和度以及测试数据资料维护,自己做了一个这样的工作平台,前端基于vue、后端基于nodejs

功能介绍

img

测试数据统计

img

上线而未上线占比、测试人员本月总任务、进行中、已完成、未完成数量、测试人员每人本周目前工时(7.5*5天)

上线记录管理

img

img

img

统计当前测试部,已上线、进行中、未开始的需求等信息

测试用例管理

img

img

日常测试用例编写、执行

接口文档管理

img

img

接口测试文档

测试工具管理

测试数据构造

img

日常测试数据构建,便于功能测试,核心封装了几个常用构造测试数据的客户端请求。

Xmind与testlink测试用例转换工具

img

将xmind思维导图,编写的测试用例转成testlink导入格式(.xml)

二维码生成、解析

img

常用于将文本内容、特别是APP下载地址,转成二维码图片,供手机扫描直接使用

接口测试

img

支持基于http/https、websocket、GraphQl协议接口

sop服务分支使用管理

img

img

多个业务线、多个测试环境,时长用于多个不同分支使用,便于记录当前每个环境使用哪个分支代码

测试报告管理

img

同步CI jenkins服务器报告数据,newman接口测试报告、mochawesome UI自动化测试报告

img

测试文档管理

img

img

保存相关测试文档,目前主要是以测试工具、框架技术资料文档为主

数据库管理

表结构查看

通过网页配置好数据库访问参数,快速查看数据表结构(无需安装破解任何数据库客户端软件)

img

img

img

img

数据库命令执行

img

img

日常测试经常使用的数据库命令脚本,可以放在这边管理,用于测试人员学习、使用

img

支持页面执行数据库命令脚本

img

img

支持保存执行配置信息

脚本代码管理

img

img

产品原型管理

公司产品经理,可以将原型文档压缩包,通过这个入口上传到服务器,测试、开发人员直接通过点击列表上面相应原型链接访问原型文档,无需再本地化管理原型文档

img

img

支持上传历史记录,新旧版本都可以快速查看到

img

img

打开后的原型文档地址,就是平台服务器后台地址

img

工单管理

管理客服、门店等线下反馈的跟进问题。

img

img

网址导航

img

常用测试网址,统一记录管理

系统基础数据管理

img

比如:测试人员基础数据,用于其他功能进行选择分配

声明

转载请注明出处:https://liyinchigithub.github.io/ 谢谢您的配合

场景法设计测试用例

场景法设计测试用例

定义

1、分析软件应用的场景(使用场景):

从用户的角度出发,从场景的角度来设计测试用例,是一种面向用户的测试用例设计方法。

2、关心用户做什么,而不是关心产品做什么。(功能测试用例相反,更关注产品功能)

优点

实用性强,贴近用户的操作。(功能测试用例相反)

缺点

可能使用的场景不一定能对事件系列进行全面的分析,设计出来的用例不完整。(功能测试用例相反,对每个页面表单控件进行全面分析)

实例

登录

(1)场景用例:

合法账号密码,能够登录成功。

合法账号密码,被禁用后再次启用,能够登录成功。

合法账号密码,重复登录,能够登录成功。

非法账号密码,无法登录,切换为合法账号密码,能够登录成功。

(你会发现:从用户层面设计用例)

(2)功能用例:

账号输入框支持格式,是否符合需求文档要求

密码输入框支持格式,是否符合需求文档要求

登录成功,是否符合需求文档要求

登录失败,是否符合需求文档要求

错误信息提示,是否符合需求文档要求。

(你会发现:从产品层面设计用例,少部分会涉及用户场景)

我的理解(总结):

1
2
3
4
5
场景分析是通过【描述流经用例路径】来确定的过程。

这个流经过程要从【用例开始到结束遍历其中所有基本流】 。

直黑线表示基本流,是最基本、最简单的路径(软件功能按照正确的事件流实现的一条正确流程无任何错,程序从开始直到结束)。

img

遵循上图中每个经过用例的可能路径,可以确定不同的用例场景。

从基本流开始,再将基本流和备选流结合起来,可以确定以下用例场景:

场景1 基本流
场景2 基本流 备选流1
场景3 基本流 备选流1 备选流2
场景4 基本流 备选流3
场景5 基本流 备选流3 备选流1
场景6 基本流 备选流3 备选流1 备选流2
场景7 基本流 备选流4
场景8 基本流 备选流3 备选流4

用场景分析法设计测试用例的步骤

1.根据说明,画出流程图(确定基本流和备选流);

2.根据基本流和各项备选流确定场景;

3.对每一个场景生成测试用例;

4.对生成的所有测试用例重新复审,去掉多余的测试用例,测试用例确定后,对每一个测试用例确定测试数据值。

用例场景例子

购书:用户登录到网站后,进行书籍的选择,当选好自己心仪的书籍后进行订购,这时把所需图书放进购物车,等进行结帐的时候,用户需要登录自己注册的帐号,登录成功后,进行付款交易,交易成功后,生成订购单,整个购物过程结束。

第一步:画出流程图,确定基本流和备选流;

img

基本流:登录在线网站→选择书籍→放入购物车→登录账号→付款→生成订单

备选流1:用户不存在→注册用户

备选流2:密码不正确

备选流3:账户余额不足→充值

第二步:根据基本流、备选流确定场景;

场景
场景1(成功购物) 基本流;
场景2(账户不存在) 基本流、备选流1
场景3(账户密码错误) 基本流、备选流2
场景4(账户余额不足) 基本流、备选流3

第三步:对每一个场景生成测试用例;

img

第四步:对生成的所有测试用例重新复审,补充测试数据值;

img

解决postman无法下载xls并解析下载内容是否正确方案

问题

使用postman做restful api自动化测试,遇到下载excel报表,并需要解析报表内容是否正确?

解决办法

借助nodejs后端框架express写一个解析程序:
postman客户端请求服务端接口,带上相关参数;
服务端下载指定文档,解析文档内容,断言是否和客户端参数一致!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//引入接口实现模块
var express = require('express');
var bodyParser = require('body-parser');
//引入sheetJS xlsx模块
var xl = require('xlsx');
//引入node-xlsx模块
var xlsx = require('node-xlsx');
//引入文件、路径、http请求模块
var fs = require('fs');
var path = require("path");
var request = require('request');
// 实例化一个express的对象app
var app = express();
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: true })
// 告诉应用程序中间件,使用外部引入的模块中间件(内置中间件、第三方中间件、自己封装js)
// 开放客户端请求访问public目录下的资源 express.statics()是内置中间件函数,与express.json、express.urlencoder一样都是内置中间件
app.use(express.static(__dirname + "/public"), function (req, res, next) {
console.log("请求地址:" + __dirname + "/public");
console.log('请求时间:', new Date());
//释放控制权
next();
});
// 为了解析 application/json
app.use(bodyParser.json());
// 跨域设置,对所有http请求均有效
// 自定义跨域中间件
app.all("*", function (req, res, next) {
//响应头
// res.header("Access-Control-Allow-Credentials", 'true');
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With');
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
res.header("Content-Length", "2000");
res.header("X-Powered-By", ' 3.2.1');
// res.header("Content-Type", "application/x-www-form-urlencoded");
res.header("Content-Type", "application/json;charset=utf-8");
//控制权交给下一个处理程序
if (req.method == 'OPTIONS') {
//让options请求快速返回
res.sendStatus(200);
} else {
next();
}
});

var result;
/**
* @description 下载文件
* @params ''
*/
app.post('/ExportTheDetailsAndCheckTheContent', function (req, res, next) {

/**
* 第一部分:根据请求内容下载指定报表
*/
//创建文件夹目录,用于保存下载文件
let dirPath = path.join(__dirname, "download_path");
//判断文件夹是否已存在
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath);
console.log("文件夹创建成功");
} else {
console.log("文件夹已存在");
}
//创建写入流
let stream = fs.createWriteStream(path.join(dirPath, req.body.fileName + ".xls"));
//请求参数
let options = {
url: req.body.down_url + req.body.fileName + ".xls",
};
//通过request模块,pipe方法将响应结果写入文件流stream中
request(options).pipe(stream).on("close", function (err) {
console.log("文件[" + req.body.fileName + ".xls]下载完毕");
//此处特别说明:因为是异步,所以要放在请求下载生成文档之后,再进行解析excel报表
/**
* 第二部分:解析下载报表方法
* 使用sheetJS xlsx读取工作簿指定工作表的数据
* @description 获取指定单元格数据
*/

//workbook 对象,指的是整份 Excel 文档。我们在使用 js-xlsx 读取 Excel 文档之后就会获得 workbook 对象。
var workbook = xl.readFile(path.join(dirPath, req.body.fileName + ".xls"))
console.log(path.join(dirPath, req.body.fileName + ".xls"));

//获取 Excel 中所有表名
const sheetNames = workbook.SheetNames; // 返回 ['sheet1', 'sheet2']

console.log("sheetNames:" + sheetNames);
//获取指定工作表数据,返回json数据
var first_sheet_name = workbook.SheetNames[0];
var address_of_cell_A2 = 'A2';
var address_of_cell_B2 = 'B2';
var address_of_cell_C2 = 'C2';
var address_of_cell_D2 = 'D2';
var address_of_cell_E2 = 'E2';
var address_of_cell_F2 = 'F2';
var address_of_cell_G2 = 'G2';
//获取工作表
var worksheet = workbook.Sheets[first_sheet_name];
//找到所需的单元格
var desired_cell_A2 = worksheet[address_of_cell_A2];
var desired_cell_B2 = worksheet[address_of_cell_B2];
var desired_cell_C2 = worksheet[address_of_cell_C2];
var desired_cell_D2 = worksheet[address_of_cell_D2];
var desired_cell_E2 = worksheet[address_of_cell_E2];
var desired_cell_F2 = worksheet[address_of_cell_F2];
var desired_cell_G2 = worksheet[address_of_cell_G2];
//获取值
var desired_value_A2 = (desired_cell_A2 ? desired_cell_A2.v : undefined);
var desired_value_B2 = (desired_cell_B2 ? desired_cell_B2.v : undefined);
var desired_value_C2 = (desired_cell_C2 ? desired_cell_C2.v : undefined);
var desired_value_D2 = (desired_cell_D2 ? desired_cell_D2.v : undefined);
var desired_value_E2 = (desired_cell_E2 ? desired_cell_E2.v : undefined);
var desired_value_F2 = (desired_cell_F2 ? desired_cell_F2.v : undefined);
var desired_value_G2 = (desired_cell_G2 ? desired_cell_G2.v : undefined);
console.log("ddesired_valueata:" + desired_value_A2);//输出excel单元格A2的数据
console.log("ddesired_valueata:" + desired_value_B2);
console.log("ddesired_valueata:" + desired_value_C2);
console.log("ddesired_valueata:" + desired_value_D2);
console.log("ddesired_valueata:" + desired_value_E2);
console.log("ddesired_valueata:" + desired_value_F2);
console.log("ddesired_valueata:" + desired_value_G2);

/**
* 第二部分:解析下载报表方法
* 使用node-xlsx
* @description 获取整个工作簿的数据
* 格式:[{"name":"表名","data":数据数据
*/
var list = xlsx.parse(path.join(dirPath, req.body.fileName + ".xls"));
console.log(JSON.stringify(list[0].data[1]));

//将读取的数据返回给客户端
if (!err === null) {
res.status(500).send({ data: list })
} else {
res.status(200).send({ data: list })
}

});

});


//监听端口
var server = app.listen(8004, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

参考链接:https://blog.csdn.net/q3585914/article/details/70157938

element-ui

简介

Element UI 是一套采用 Vue 2.0 作为基础框架实现的组件库,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的组件库,提供了配套设计资源,帮助网站快速成型

组件

TODO

分页

1
2


持续集成之jenkins的Job配置

常用配置

邮件正文配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 <!DOCTYPE html>    
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>

<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
本邮件由系统自动发出,无需回复!<br/>
各位同事,大家好,以下为${PROJECT_NAME }项目构建信息</br>
<td><font color="#000000">构建结果 - ${BUILD_STATUS}</font></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>项目名称 : ${PROJECT_NAME}</li>
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
<li>触发原因: ${CAUSE}</li>
<li>构建状态: ${BUILD_STATUS}</li>
<li>构建日志: <a href="${JENKINS_URL}/job/${JOB_NAME}/${BUILD_ID}/console">${JENKINS_URL}/job/${JOB_NAME}/${BUILD_ID}/console</a></li>
<li>构建 Url : <a href="${JENKINS_URL}/job/${JOB_NAME}">${JENKINS_URL}/job/${JOB_NAME}</a></li>
<li>工作目录 : <a href="${JENKINS_URL}/job/${JOB_NAME}、ws">${JENKINS_URL}/job/${JOB_NAME}/ws</a></li>
<li>项目 Url : <a href="${JENKINS_URL}/job/${JOB_NAME}">${JENKINS_URL}jenkins/job/${JOB_NAME}</a></li>
<li>本次构建脚本:${script} </li>
<li>本次构建环境:${env} </li>
<li>具体报告内容 Url : <a href="${JENKINS_URL}/job/${JOB_NAME}/HTML_20Report/${JOB_NAME}-${env}-${BUILD_ID}-index.htm">${JENKINS_URL}/job/${JOB_NAME}/HTML_20Report/${JOB_NAME}-${env}-${BUILD_ID}-index.htm</a></li>
<li>聚合报告 Url : <a href="http://10.104.113.228:8080/system/#/">http://10.104.113.228:8080/system/#/</a></li>
</ul>

<h4><font color="#0B610B">失败用例</font></h4>
<hr size="2" width="100%" />
详见附件build.log<br/>

<h4><font color="#0B610B">最近提交(#GITLAB_REVISION)</font></h4>
<hr size="2" width="100%" />
<ul>
${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
</ul>
详细提交: <a href="${JENKINS_URL}/job/${JOB_NAME}changes">${JENKINS_URL}/job/${JOB_NAME}/changes</a><br/>

</td>
</tr>
</table>
</body>
</html>

参数化构建使用扩展参数插件(Extended choice parameter)

Choose Source for Value

Groovy script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

//读取目录结构
def locat = "/data/jenkins/workspace/资产售后-流程脚本/脚本"
def dir = new File(locat)
Set<String> artifacts = new TreeSet<String>()
dir.eachDir { directory ->
if (directory.absolutePath.contains("postman") || directory.absolutePath.contains("jmeter")) {
for (File f : directory.listFiles()) {
String script = f.getAbsolutePath()
artifacts.add(script)
}
}
}
List<String> result = new ArrayList<String>()
result.addAll(artifacts)
return result

可以获取以文件夹命名存放的脚本名称,作为jenkins参数来选择,用于构建jenkins job

img

shell脚本获取文件件目录

获取postman或jmeter下的脚本内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env bash
#获取执行脚本集合
arr=(${script//,/ })
#调试输出每个集合元素
echo -----${arr[@]}
#获取集合元素个数
length=${#arr[@]}
#判断个数是否大于0,相当于判断jenkins界面脚本文件夹参数$script是否勾选了
if [ $length > 0 ]
then
#循环调用执行postman/jmeter脚本
for i in ${arr[@]}; do
# =~代表正则匹配
if [[ $i =~ postman ]]
then
# ls 返回目录下的所有文件
files=$(ls $i)
#遍历所有的文件夹
for j in $files
do
# if [ -z $String ] 代表如果字符串为空 这边只运行$testFilesIncluded所包含的文件(有配置的情况)和只获取后缀为postman_collection.json的文件
if ( [ -z "$testFilesIncluded"] || [[ $testFilesIncluded == *$j* ]] ) && [[ $j == *.postman_collection.json ]]
then
# % 去除最短的向后匹配 %%去除最长的向后匹配 #去除最短的向前匹配 ##去除最长的向前匹配 eg:http://landoflinux.com/linux_bash_scripting_substring_tests.html
envPrefix=${j%.postman_collection.json}
reportPrefix=${envPrefix}
# newman 运行脚本文件 输出cli和html的测试报告
#切换当前目录到$WORKSPACE
cd ${WORKSPACE}
#执行newman命令,其中报告输出位置文件名使用到变量。当前shell脚本定义的变量:${reportPrefix};jenkins用户自定义变量:${env};jenkins系统变量:${JOB_NAME}、${BUILD_ID};
newman run $i/$j -e $i/${env}.postman_environment.json --delay-request 1000 --reporters cli,html,json,junit --reporter-json-export ${BUILD_ID}"-"jsonOut.json --reporter-junit-export ${BUILD_ID}"-"xmlOut.xml --reporter-html-export ${JOB_NAME}"-"${env}"-"${BUILD_ID}"-"index.htm
fi
done

fi
done

fi

自动化录制工具

简介

你想象过可以让任何一个完全没有自动化经验的人,可以1分钟录制出可读性高,且强大的自动化脚本工具吗?

还真存在这么一款UI自动化录制工具,它就是由alibaba Macaca团队开源的UiRecorder。

这是一款基于WebDriver、Chrome浏览器、NodeJs等方案共同打造的零成本自动化解决方案。

基于几乎零成本的【录制方案】,让所有开发和测试能够最低成本的获得自动化测试的能力,把重复又枯燥的测试工作全部交给计算机,彻底的提高测试效率,解放我们的生产力。

跨平台:适用于Windows、linux、mac

三端录制:PC、移动端(android、iOS)

(也许你看到标题第一反应是Selenium IDE,但实际上Selenium IDE已停止维护好多年了,UI Recorder 要比Selenium IDE更加强大,支持多端录制)

环境

安装配置JDK环境变量

JDK 8.0

安装配置Node环境变量

Node.js 10

More info: uirecorder官网

安装

mocha安装

(此处说明下:录制的脚本运行环境基于mocha框架,因此需要安装mocha)

1.全局安装mocha

windows

(1)打开终端窗口:开始-运行-cmd 右击以管理员身份运行

1
npm install mocha -g

(2)安装完成后,配置到系统变量
打开系统变量path 末尾加入C:\Program Files\nodejs\node_global 确定保存

(3)检查mocha是否安装成功

1
mocha -V

mac

(1)打开终端窗口

1
npm install mocha -g

(2)检查mocha是否安装成功

1
mocha -V

2.全局安装uirecorder

此处说明下:安装uirecorder时,需要下载chrome浏览器驱动会超时报错,因为这边下载默认从谷歌官方。

解决办法:设置淘宝镜像下载路径

windows执行

1
set CHROMEDRIVER_CDNURL=http://npm.taobao.org/mirrors/chromedriver

mac执行

1
export CHROMEDRIVER_CDNURL=http://npm.taobao.org/mirrors/chromedriver

windows

(1)打开终端窗口:开始-运行-cmd 右击以管理员身份运行

1
npm install uirecorder -g

(2)检查uirecorder是否安装成功

1
uirecorder --version

img

mac

(1)打开终端窗口

1
npm install uirecorder -g

(2)检查uirecorder是否安装成功

1
uirecorder --version

3.全局安装mochawesome

Uirecorder报告是借助mochawesome来展示脚本执行结果,再回放录制脚本的时候使用只要带入参数mochawesome

(1)打开终端窗口:开始-运行-cmd 右击以管理员身份运行

1
npm install mochawesome -g

4.chrome浏览器安装(如果已安装要升级到最新版)

下载地址

5.移动端录制需要安装配置环境android SDK 、ios开发工具

可以参照appium-doctor

appium-doctor

框架

实际上UiRecorder录制生成的脚本,是一个基于nodejs+mocha+jwebdriver框架的自动化工程,回放脚本是通过执行mocha命令并附带mochawesome报告参数来生成测试报告

基础操作(录制与回放)

web

1.录制

(1)以文件夹来划分录制项目模块

①新建一个文件夹A,用来放录制脚本存放位置

②打开终端窗口:开始-运行-cmd 右击以管理员身份运行,进入到新建文件夹A目录下

(2)Uirecorder初始化

①在新建的文件夹A下,新建一个文件夹test,用于存放录制的脚本

②执行初始化

打开终端窗口:开始-运行-cmd 右击以管理员身份运行

1
2
cd test  
uirecorder init

此处说明下:uirecorder初始化会自动生成配置文件,建议使用默认配置,一路回车即可。
初始化完成后会自动安装相关依赖

初始化

自动安装浏览器驱动

初始化完后当前目录下生成以下文件
如下所示:

1
2
3
4
5
6
7
8
9
10
uirecorder初始化文件夹说明
Commons:公共脚本文件夹
Diffbase:图片对比文件夹
node_modules:node核心文件库
reports:测试报告文件夹
sample:示例脚本目录
screenshots:测试执行截图保存目录
uploadfiles:附件保存文件夹,比如写信页上传附件,要求把附件先放入该目录;
config.Json:运行配置文件,比如IP,浏览器
run.bat:运行测试,执行该命令会运行所有的测试脚本

(3)录制脚本

打开终端窗口:开始-运行-cmd 右击以管理员身份运行

1
uirecorder start

①Uirecorder配置向导会提示输入要使用的测试脚本名称:

1
2
例如:输入test/test.1.js
表示录制的脚本要存放在test文件夹下的test.1.js

②配置向导提示你输入是否同步校验浏览器:

1
2
例如:输入Y
表示启用同步校验浏览器

③配置向导提示你输入浏览器大小:

1
2
例如:输入maximize
表示窗口最大化

(配置向导完成之后会自动打开chrome页面(同时打开校验页面,校验页面没有内容)

④输入打算录制的页面地址

1
例如:输入百度地址https://www.baidu.com

⑤点击【开始录制】按钮,进入录制模式

工具面板

录制页面会显示一个uirecorder工具面板,此时你的所有操作均会被录制下来。
例如:鼠标(点击事件)、键盘(按键事件)等操作

⑥期间,可以使用工具面板上面的功能:

属性开关、属性黑名单、添加悬停、添加断言、执行JS、添加延迟、脚本跳转、结束录制

工具面板

工具面板
⑦每录制成功,屏幕右下角会弹出执行成功的提示

⑧录制结束

点击【结束录制】按钮,即可结束录制,自动关闭浏览器

同时在test目录下生成一个脚本文件,文件名称便是在启用录制时,咱们命名的脚本名称

终端窗口也会同步显示录制记录结果

终端窗口

2.回放脚本

此处说明下:回放脚本借助mocha框架回放js脚本,并生成mochawesome结果报告,所以需要你在之前环境准备过程中安装mochawesome node模块

①安装mochawesome

开始-运行-cmd,以管理员身份运行

1
npm install mochawesome -g

②安装selenium-standalone与浏览器驱动

此处说明下:回放脚本需要启动selenium-standalone服务,实际上我们刚才在uirecorder init 初始化时,已下载安装了selenium-standalone和相关浏览器驱动)。

(启动selenium-standalone服务有两种方式:一种是独立包方式、另一种是全局node模块模式,建议使用全局node模块模式)

【第一种方式】独立包方式 (优势:可以手动更换浏览器driver)

(如果你的浏览器是非安装版,双击即可直接打开,并且浏览器版本和浏览器驱动版本想要固定不变,可以采用这种方式)

【A】下载selenium-standalone到本地,下载地址(建议放置放录制脚本目录下)

img

【B】启动selenium-server-standalone

打开终端窗口:开始-运行-cmd 右击以管理员身份运行

1
cd 存放selenium-server-standalone.jar包路径下

1
java -jar selenium-server-standalone-3.9.1.jar

img

【C】下载chromedriver到本地,下载地址

img

此处说明下:chromedriver版本与你本地电脑安装的chrome版本需要对应,谷歌官方对应版本查看地址https://sites.google.com/a/chromium.org/chromedriver/downloads

不能翻墙可以看这里
(我本地chrome浏览器版本是68, 因此下载chromedriver版本应该是2.40)

【D】下载后双击chromedriver打开服务

img

img

第二种方式:全局安装

此处说明:安装前需要设置淘宝镜像,因为chromedriver默认是从谷歌官网下载下来,未设置淘宝镜像会报超时。(如果你有翻墙那是最好,但建议你关闭翻墙代理,使用淘宝镜像地址进行下载)

【A】全局安装node selenium-standalone模块

1
npm install selenium-standalone -g

img

【C】 安装selenium驱动、浏览器驱动

1
selenium-standalone install

【B】 启用服务

1
selenium-standalone start

img

③执行回放脚本

此处说明下:回放脚本方式有两种第一种借助mocha框架执行指定位置脚本,第二种使用bat文件

【第一种方式】推荐使用

【A】运行单个脚本
开始-运行-cmd,以管理员身份运行

1
mocha 脚本路径名称 --reporter mochawesome

例如:

1
mocha C:\Users\lyc\Desktop\A\test\test.1.js --reporter mochawesome

img

此处说明下:回放脚本前,如果你使用独立方式安装selenium-standalone,那么需要开启selenium-server-standalone服务、开启chromedriver服务,且不能关闭。

【B】运行所有脚本

开始-运行-cmd,以管理员身份运行

1
2
3
cd C:\Users\lyc\Desktop\A   //目录切换至新建文件夹A

mocha --reporter mochawesome

img

此处说明下:mocha框架自身默认会执行以test命名的文件夹下所有脚本。

【第二种回放方式】

run运行测试用例
开始-运行-cmd,终端进入存放脚本的文件夹A,终端输入

1
run.bat

运行所有脚本
此处说明下,运行所有脚本需要配置/*/.spec.js,否则会报错

1
run.bat test\test.1.js

运行单个脚本

此处说明下:第二种方式windows平台使用run.bat 而linux平台使用 run.sh 此方法与第一种方式其实一样,只是把命令行封装到bat或sh文件中。

mobile

1.环境准备

(1)Android平台

①JDK(前面步骤我们已配置好)

②安装macaca

1
npm i -g macaca-cli

安装成功会显示:

macacalogo

macaca参考

③安装macaca-android

【A】设置淘宝镜像

1
npm config set registry http://registry.npm.taobao.org/

此处说明:不设置淘宝镜像,node将会从谷歌上面下载相关内容,在没有翻墙前提下,执行下一步【B】将会报超时下载失败。

【B】执行安装

1
npm i macaca-android -g

检查环境

macaca doctor

img

④启动macaca服务

1
macaca server --port 4444 --verbose

img

⑤Android sdk 环境变量配置

参考:https://jingyan.baidu.com/article/15622f2434bc5cfdfcbea51c.html

⑥安装Gradle

下载地址:https://gradle.org/releases/在此页面下载zip包,解压并加入环境变量

【A】PATH中加入%GRADLE_HOME%\bin

img

【B】新增GRADLE_HOME变量,变量值为Gradle存放位置

【C】检查是否配置成功
img

(mac直接安装即可)

(2)iOS平台(需要使用Mac系统)
安装配置

1
2
Xcode
Xcode Command Line Tool

此处说明:
①iOS安装包使用格式为.app(不能用.ipa)

②iOS需要在mac系统上配置,配置请参考:https://testerhome.com/topics/13273

③安装包使用格式为.apk或.zip(如果是.zip会提示你选择是android还是ios平台的安装包)

此处说明:如果你是从零开始,环境配置可以参考:

JDK https://jingyan.baidu.com/article/6dad5075d1dc40a123e36ea3.html

Android SDK https://jingyan.baidu.com/article/15622f2434bc5cfdfcbea51c.html

Android ADB https://jingyan.baidu.com/article/17bd8e52f514d985ab2bb800.html

Gradle https://jingyan.baidu.com/article/73c3ce2816eae9e50343d9fe.html

2.录制

(1)新建一个文件夹,比如命名为Mobile

(2)终端cd 进入Mobile文件夹内

(3)uirecorder 初始化

1
uirecorder init --mobile

(4)提示输入app安装包名(带格式后缀)

(5)输入安装包回车后,弹出浏览器,开始录制

1
uirecorder --mobile sample/test.spec.js

img

img

(6)开始录制

①新建一个文件夹命名为test,用于存放录制的脚本

②把测试包放入mobile文件夹下

此处说明下:
【A】android使用.apk格式安装包

【B】iOS使用.app格式的安装包(并不能用.ipa格式)

img

③uirecorder –mobile test/test.spec.js

参数说明:
–mobile 表示录制移动端

test表示脚本位于test文件夹

test.spec 表示用例脚本名称

【A】输入要进行录制测试包包名

【B】弹出浏览器,同时手机端弹出app安装(有些手机系统安全机制需要先输入安装密码执行安装,比如vivoX21)

img

如果你使用的是zip压缩包,会提示你选择android还是ios平台

img

【C】操作浏览器即可进行录制,录制工具使用方法和web端一样(详见第六部分介绍)

img

【D】每录制成功一步,屏幕右上角会有相应提示

img

【E】你还可以通过工具面板输入文字、后退、弹窗命令处理、断言、延迟等待、跳转到另一个之前录制的脚本、结束录制

img

【F】录制完毕,我们还可以通过编辑器打开Mobile文件夹,修改脚本内容,删除某些录制步骤

img

(7)注意事项:某些控件无法录制

有时候由于控件排版问题,或其他原因导致无法识别到元素,既是uirecorder识别到了,但点击也没反应。

解决办法:
修改脚本,直接在脚本内手动输入该元素(元素定位可以是用appium或者macaca inspect)

例如:录制某个按钮点击无效

通过编辑器打开并找到这个脚本位置,修改其元素选择器内容,如:xpath等,并直接执行mocha命令,通过浏览器进行调试。
如下图所示:

修改前

img

修改后

img

3.回放

(1)使用mocha命令
①全部脚本:

1
mocha --reporter mochawesome

②指定脚本:

1
mocha ./mobile/test/4S金融下单.js --reporter mochawesome

参数说明:–reporter mochawesome为生成报告参数,执行命令后会在根目录下生成mochawesome报告文件。
如下图所示:

img

(2)使用批处理命令

全部脚本:

run.sh ( Linux|Mac )

1
sudo sh run.sh ./mobile/test/4S金融下单.js

run.bat ( Windows )

1
run.bat ./mobile/test/4S金融下单.js

指定脚本:

1
2
run.sh sample/test.spec.js ( Linux|Mac ) 
run.bat sample/test.spec.js ( Windows )

高级使用(工具面板)

属性开关

进入录制页面后,属性开关全部为默认开启状态,因此在你点击任意DOM时,DomPath会自动选择属性并展示。
如下图所示:

鼠标点击页面DOM“Email:”,DomPath展示为://td[text()=”Email:”]

img

若将属性开关text关闭后,DomPath会自动选择其他属性并展示。(点击属性开关text,text置灰并关闭,再次点击点亮并开启)

img

此处说明下:建议都开启属性开关,避免元素无法定位。

属性黑名单

因为某些属性值是随机或不稳定,我们无法录制出稳定的CSS选择器路径,因此我们可以使用黑名单过滤这些属性值。

提示: 属性黑名单是一个正则表达式, 可以类似这样使用:/attr_\d+/

a)可以在UI Recorder初始化时,属性值黑名单正则设置时,输入黑名单正则表达式,如:/attr_\d+/

img

b)也可以在录制页面,属性黑名单处,输入黑名单正则表达式,如:/attr_\d+/

img

添加悬停

当页面中存在二级目录等类似情况时,需要鼠标悬停操作,UI Recorder就提供了添加悬停操作,可单次悬停或者多次添加悬停。依据需求可自行选择实现方式。
a)单次悬停,点击“添加悬停”按钮,鼠标变为绿色锁定元素,单击后结束悬停。

img

b)多次添加悬停,按下Ctrl键,点击添加悬停按钮,进入悬停模式,可释放Ctrl键;点击需要悬停的DOM控件(可多次添加悬停)。
按下Esc键 或 点击结束悬停按钮, 退出悬停模式。
悬停模式下,可对元素进行断言操作,点击添加断言按钮,点击需要断言的DOM控件。

img

添加断言

UI Recorder支持丰富的断言类型: val、text、displayed、enabled、selected、attr、css、url、title、cookie、localStorage、sessionStorage
步骤:点击添加断言按钮,点击需要断言的DOM控件。弹出添加断言的窗口,在窗口中填入相关信息。点击确认,添加断言成功。

#延迟时间,默认为300ms

#断言类型,支持以上列出的12种类型,根据自己的需要选择。

#断言DOM,显示鼠标定位的元素

#比较方式,支持7种类型:equal、notEqual、contain、notContain、above、below、match、notMatch,,根据自己的需要选择。

#断言结果,填写期望结果

img

脚本中设置断言的方法

1
2
3
4
5
6
7
8
//断言是否登录成功
it('expect: text, //*[@text="工作台"], equal, 工作台', async function(){
await driver.sleep(300).wait('//*[@text="工作台"]', 30000)
.text()
.should.not.be.a('error')
.should.equal(_(`工作台`));
});
//等待

使用变量

(1)添加变量有2种方式,一种方式是在config.json文件中直接编辑添加,另一种方式是在录制页面,点击使用变量,选择创建变量。

提示: 所有变量字符串均支持JS语法的模板字符串,例如:, ${new Date().getTime()}

1)编辑config.json,设置变量。

如下图:此处设置了4个变量,分别为:username、password、test、dev

img

2)在录制页面,创建变量。

如下图所示,在录制页面,点击使用变量,弹出使用变量弹窗,使用方式选择为插入变量,变量名,点击添加变量,即可设置变量。

img

img

(2)更新变量,在录制页面,点击使用变量,弹出使用变量弹窗,使用方式选择为更新变量。
选择想要更新的变量名username,选择取值方式(与断言方式一致,为12种类型),取值正则,即可更新已有变量。

img

(3)使用变量,在录制页面,点击使用变量,鼠标定位需要插入变量的DOM,弹出使用变量弹窗,使用方式选择为插入变量
选择想要插入的已有变量名username,页面自动展示username相关信息。

img

鼠标定位需要插入变量的DOM为Email的输入框,点击使用变量框的确认按钮,变量添加成功。在输入框中插入该变量username

img

插入变量的DOM,若要添加断言,可使用变量字符串:

img

执行JS

在录制页面,点击执行JS按钮,可输入一段js代码,并执行,例:document.title=”test”

img

输入js代码后,点击确认,浏览器会立即执行该js代码,如下图,title更改为test。

img

添加延迟

在录制页面,点击添加延迟按钮,可在录制过程中添加延迟时间,在添加延迟弹框中,输入延迟时间,并执行,默认为1000ms。

img

在脚本中设置延迟

1
2
3
4
//等待
it('sleep: 3000', async function(){
await driver.sleep(3000);
});

脚本跳转

录制过程中,可录制一些公用脚本,例如登录脚本、固定流程脚本等等。
调用公共脚本方法:在开始页面的时候输入sample/test.login.js,或者在录制中间页面时点击脚本跳转,脚本跳转弹框中输入sample/test.login.js
当sample/test.login.js加载完成后,继续别的步骤的录制。

img

脚本中设置跳转的方法

1
callSpec('test/脚本名称.js')

img

控制台显示
img

上传文件

UI Recorder仅支持Native文件上传, 不支持FLASH上传
直接点击“选择文件”按钮或点击“Upload file”, 占位按钮必需要用role或data-role标注为upload

img

上传的文件必需保存在/uploadfiles/文件夹中。

img

测试数据和脚本分离

demo中以json来管理测试数据

img

img

脚本修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

//(一)Web
//打开页面
it('url: http://adminpre.alspark.cn/#/login', async function(){
await driver.url(_('xxxxxxx'));
});

//'xxxxxxx' 是一个网页地址,例如http:”www.baidu.com”

//向下滚动屏幕
it('scrollElementTo: #app div.app-iframe-container, 0, 539', async function(){
await driver.sleep(300).wait('#app div.app-iframe-container', 30000)
.sleep(300).scrollElementTo(0, 539);
});

//(0, 539)是滚动的幅度坐标

//置顶滚动屏幕
it('scrollElementTo: #app div.app-iframe-container, 0, 0', async function(){
await driver.sleep(300).wait('#app div.app-iframe-container', 30000)
.sleep(300).scrollElementTo(0, 0);
});

//假设从主窗口0点击某个按钮,弹出了一个子窗口1,当前同时存在主窗口0和子窗口1

//切换至子窗口1
it('switchWindow: 1', async function(){
await driver.sleep(500).switchWindow(1);
});

//关闭窗口
it('closeWindow: ', async function () {
await driver.closeWindow();
});

//切换到主窗口
it('switchWindow: 0', async function () {
await driver.sleep(500).switchWindow(0);
});

//0是主窗口、1是子窗口、之后打开的子窗口以此类推。

//切换到页面iframe
it('switchFrame: #iframe0201000000', async function(){
await driver.switchFrame(null)
.wait('#iframe0201000000', 30000).then(function(element){
return this.switchFrame(element).wait('body');
});
});


//切换出iframe 切到null即是且至主页面
it('switchFrame: null', async function(){
await driver.switchFrame(null);
});



//(二)Mobile

//点击
it('tap: //*[@resource-id="com.maimaiche.dms:id/start_button"]', async function(){
await driver.wait('//*[@resource-id="com.maimaiche.dms:id/start_button"]', 30000).sendElementActions('tap');
});


//输入账号
it('sendKeys: 15022676605', async function(){
await driver.sendKeys(_(`15022676605`));
});


//滑动
it('drag: 滑动欢迎页', async function(){
await driver.sendActions('drag', {fromX: 1016, fromY:1157, toX:245, toY:1134, duration: 0.73});
});


//三)通用
//等待
it('sleep: 3000', async function(){
await driver.sleep(3000);
});



//等待页面加载,断言是否出现页面加载错误或者超时等其他情况
it('waitBody: ', async function(){
await driver.sleep(500).wait('body', 30000).html().then(function(code){
isPageError(code).should.be.false;
});
});


//断言是否登录成功
it('expect: text, //*[@text="工作台"], equal, 工作台', async function(){
await driver.sleep(300).wait('//*[@text="工作台"]', 30000)
.text()
.should.not.be.a('error')
.should.equal(`工作台`);
});

注意事项与常见问题

1
2
3
4
5
6
7
注意事项:
(1)禁止直接手动修改地址栏中的URL
(2)禁止使用TAB切换焦点
(3)不要使用双击, WebDriver兼容性不好
(4)不要使用鼠标选择部分文本, WebDriver兼容性不好
(5)不要手动切换至背景窗口。(目前最新版貌似没有影响)
(6)不要点击非关键区域, 仅录制关键步骤,不然增加脚本长度

报告

在目录A下会自动生成一个mochawesome-report文件夹,报告格式有两种,一种html另一种json格式

img

img

故障排除

(1)【环境与安装】【待解决】Node 版本10.13、15 uirecorder 初始化安装依赖会报错
解决方案:请使用低与10.13、15版本的node,比如:10.8 版本支持uirecorder
https://nodejs.org/zh-cn/download/releases/

(2)【环境与安装】【已解决】报错SyntaxError: missing ) after argument list
解决方案:升级到NodeJs v7.10以上版本

(3)【环境与安装】【已解决】报错session not created exception from disconnected: unable to connect to renderer
解决方案:系统hosts文件中添加127.0.0.1 localhost

(4)【环境与安装】【已解决】已经存在旧版本部分文件,执行安装报错后,查看版本提示失败。
解决方法:
node删除文件,重新安装,重新配置node环境。

img

(5)权限不够报错

img

windows系统特性,需要手动授权C盘的ProgramFiles文件
如下图所示:勾掉只读,确定保存

img

(6)【环境与安装】【已解决】安装中提示编译失败 缺少websocket

解决方法:npm i websocket -g

img

(7)【环境与安装】【已解决】初始化页面卡住

img

解决方法:把node 卸载重装(v.10.8.0)

img

目前最新版node(v10.13)和最新版uirecorder(2.5.46)不兼容,需要安装node版本低于10.12版本。

(8)【环境与安装】【已解决】安装npm i selenium-sandalone -g 超时报错

解决方案:

①设置淘宝镜像
npm config set registry http://registry.npm.taobao.org/

②执行

【A】卸载之前安装 npm uninstall selenium-sandalone -g

【B】清缓存 npm cache verify

【C】重新执行安装 npm install selenium-standalone -g

img

(9)Selenium-standalone install 过一会报错

执行安装命令后

img

img

原因:设置淘宝镜像没有生效,从第一图看出还是在谷歌上面下载驱动,所以超时报错。

解决方案:

①将下载链接设置为淘宝镜像,执行:

1
set CHROMEDRIVER_CDNURL=http://npm.taobao.org/mirrors/chromedriver

②管理员账号权限下,执行:

1
npm info underscore  //生效设置

执行

1
selenium-standalone install --drivers.chrome.version=2.46 --drivers.chrome.baseURL=http://npm.taobao.org/mirrors/chromedriver

注意chromedriver版本号2.46要和你本地谷歌浏览器对应。
(chromedriver版本与chrome浏览器版本对应,参考:https://sites.google.com/a/chromium.org/chromedriver/downloads

img

③执行

【A】卸载之前安装 npm uninstall selenium-sandalone -g

【B】清缓存 npm cache verify

【C】安装 npm install selenium-standalone -g

【D】安装 selenium-standalone install

【E】安装 selenium-standalone start

(10)npm i 或npm install 提示不是内部命令

解决方案:

①系统环境变量NODE_PATH路径设置不正确

②系统环境变量PATH中 nodejs的路径设置不正确

(11)npm install uirecorder -g安装成功,但是执行uirecorder –version后提示不是内部命令或外部命令
解决方案:

①检查C:/ProgramFiles/nodejs/下是否有uirecorder.cmd文件

②检查系统环境变量NODE_PATH的路径,并通过文件夹打开进入到该路径下查看是否有uirecorder文件夹。

以上均没有的话,可能是你node安装位置和环境变量不一致。

(12)【web端】【已解决】报错ChromeDriverServices\nBuild
解决方案:

①浏览器驱动chromedriver.exe本版本与本地浏览器版本对应一致。

【A】chromedriver下载地址:
https://npm.taobao.org/mirrors/chromedriver/

【B】chromedriver与chrome版本对应地址:
https://sites.google.com/a/chromium.org/chromedriver/downloads

②下载一个独立的chromedriver并设置为本地系统全局变量。

img

(13)【web端】【已解决】selenium-standalone 服务未启动便开始录制。

img

(14)【web端】【已解决】web录制遇到切换至iframe如果手动更改,需要执行iframe切出,await driver.switchFrame(null);

(15)【web端】【已解决】web录制弹出子窗口,关闭子窗口会退出录制状态。因此子窗口在录制过程中不要关闭(一旦关闭,之前录的都不会保存)

img

(16)【web端】【已解决】web上传文件的附件需要放置在目录uploadfiles下。录制后的脚本会通过这个文件夹去查找是否有这个待上传的文件

img

脚本中读取的路径也是从uploadfiles目录中查找

img

(17)【web端】【已解决】web上传文件的附件需要放置在目录uploadfiles下。录制后的脚本会通过这个文件夹去查找是否有这个待上传的文件

(18)【web端】【已解决】web下载文件,浏览器使用chrome不会弹出保存文件弹窗,使用firefox会弹出保存文件弹窗,可以通过firefox设置页修改下载文件保存位置来解决。

(参考:https://jingyan.baidu.com/article/9f63fb9171e81bc8400f0e07.html)

(19)【web端】【已解决】默认录制等待时间最长30秒,有时下载步骤可能会超过30秒,可以修改脚本这边的等待时长,如下图所示:

img

(20)【移动端】【已解决】macaca server没有启动起来或者启动端口非4444

img

(21)【移动端】【已解决】macaca server没有启动,录制、回放都要开启macaca server 端口指向4444

macaca server –port 4444 –verbose

img

(22)【移动端】【待解决】无法输入中文(车码头APP 4S金融下单输入客户名称)

(23)【移动端】【待解决】移动端无法输入特殊符号。(车码头APP登录账号使用邮箱 )

(24)【移动端】【已解决】安装iOS .app测试包报错提示手动安装。(使用.app格式包)

img

iOS测试包必须是.app格式,如果使用.ipa会报这个错

解决办法:将.ipa改成.app格式。

①将.ipa格式后缀改成.rar或.zip

②解压

③进入文件夹,应该是一个.app格式的文件

④将这个.app格式的文件压缩成.zip

⑤重命名testapp.app.zip

img

中文手册

中文手册

声明

转载请注明出处:https://liyinchigithub.github.io/ 谢谢您的配合

自动化测试框架究竟哪家强?

前言

自动化测试框架很多,测试人都知道有JUnitTestNGSelenium+WebDriverAppium等。再具体点,如果说通用的测试框架,您可能会想到STAF+STAX;如果说Android App自动化测试框架,除了Appium,您可能还会想到Robotium、Selendroid、ATAF等;如果说API自动化测试框架,您可能会说Postman没有竞争对手;如果说验收测试框架,您可能会想到Fitnesse;如果要说流行的BDD自动化测试框架,CucumberCalabashJbehave也鼎鼎有名。究竟哪家自动化测试框架最强呢?

答案是Node.js你一定很惊讶,这哪是测试工具啊,这不就是一个JavaScript引擎吗。其实这指的是Node.js生态(未来趋势)。你可以在Node.js中找到各类强大的自动化框架,开源库,能够满足一个精力充沛的IT男对自动化测试的所有狂野的想象。测试的类型从API、Web、手机移动端和Windows应用。其实我们为什么为一些测试工具争个你高我低呢,博采众长、取万物之精华不是更有利吗?Node.js就是这样一个环境,所有优秀的工具都愿意在Node.js社区贡献自己的力量。

cucumber

下面我们来看个究竟。

API

例如,如果你要做RESTful API测试,Node.js提供了很多框架,例如Request、Axios、got等,从功能完备的到轻量级的都有。这些框架都有着非常高的人气,例如有图为证,got库最近7天就有300万的下载量,而Request库只会更高:

Web

如果你要做Web UI测试,那可选的就更多了。经典的selenium-webdriver,最近7天也达到了近100万的下载量。还有很多类似于selenium-webdriver的库,如webdriveriowd等,提供了不同程度的简化。

还有一个最近很火的Puppupteer ,是Google Chrome团队开源的端到端自动化测试框架,可以做UI自动化测试,也可以做为爬虫工具。作为Headless方式运行,Puppupteer更快,更省资源,它主要支持nodejs开发脚本。

(你可能会好奇爬虫不是用python吗?其实Java、JavaScript也都可以实现爬虫,爬虫爬的是前端页面的元素内容,而前端页面是由JavaScript构成,当然谁更适合爬虫一目了然,nodejs生态的领域会超出你们的想象,关于node爬虫你可以参照这里玩下)

selenium-webdriver

webdriverIO

移动端

手机移动端测试,就不能不说应用的最广泛的Appium。Appium很大,包含了iOS、Android等系统的自动化测试库。你只要象其它的库一样,在命令行输入”npm install appium”就有了。

阿里对Node.js有特别的偏爱,做了很多Node.js的开源库,其中Macaca就是阿里发布的针对移动端测试的工具。它也包括Node.js的客户端。可以测试 Native, Hybrid, H5 等多种应用类型,提供客户端工具和持续集成服务。

实际上webdriverIO也可以应用到移动端,并且也被Appium纳入了官方demo中。

对于Windows 应用,微软也来支援,发布了WinAppDriver它可以在Node.js通过WebDriver端直接调用,测试Windows应用。

其它框架

除了这些提供自动化技术的库,还有一个很重要的部分就是自动化驱动的框架。Node.js提供了很多框架,包括mocha、jasmine、cucumber.js。其中mocha、jasmine既可以适用于自动化单元测试,也可以驱动TDD(测试驱动)、BDD(行为驱动)的开发。而cucumber.js是专业做行为驱动的自动化测试的工具,最近在开源社区很活跃,已经更新到最新的4.0版本。

测试完了要显示报表,不要急,也有做的足够专业的开源报表显示工具cucumber-html-reporter,能够针对Cucumber.js生成多种格式的报告。

JavaScript生态

在整个Github项目中,用的编程语言最多的就是JavaScript,下面是Github项目中的语言排名。

俗话说的好,女怕嫁错郎,男怕入错行,而IT男最怕的就是选错技术,选错了技术不但意味着工作选择、薪资都有可能被限制,而且意味着巨大的学习成本的浪费。

从学习编程以来,本人学了很多的技术都被淘汰了:大学里学asp.net,现在几乎不用了,后来自学了C,也很少人用了,毕业的时候感潮流学了VB,现在连微软自己都不用了。网站开发的时候学了ASP、后来用的Silverlight都逐渐被淘汰。测试开发的时候用VBScript(QTP)、C (LoadRunner)现在都越来越不流行。只能苦逼的不断的学习。

而JavaScript从十几年前开始用到现在仍旧不光流行,而且是越来越火,从网页、后端,到跨Windows、Linux平台应用的开发,到开发原生移动端应用都可以用JavaScript搞定。所以现在它成为了全栈工程师的首选。不管你现在是全栈工程师、还是仅仅在做测试,选择JavaScript都能满足需要。如果你对Node.js还有怀疑可以看看这篇文章,了解一下Node.js的强大:

不只是Web:十大令人振奋的Node.js项目
https://cloud.tencent.com/developer/article/1064884

工具整合

PC客户端开发可以使用electron

移动端开发可以使用weex

前端web、H5可以使用VueElement-ui

自动化测试框架那就更多了。。。

综上看来Node.js完全可以满足各类自动化测试的需求。但是还是有很多同学觉得为难,这么多开源工具要整合起来有点难,而且Node.js作为纯命令行工具,也对初学者也不够友好。这种担心是很合理的,这是很多开源工具的都有的问题。

CukeTest

现在有了一个将所有这些开源工具在一起使用的机会。一个对个人用户都免费的工具,CukeTest,可以将所有这些框架都整合在一起使用。

不仅因为它具有易于编写测试用例的可视化界面,根据测试用例一键生成自动化测试代码框架,运行完成后自动生成测试报告、web自动化支持屏幕录制功能,同时也支持使用csv文件导入导出功能支持数据驱动。下面就呈上证据:

可视化界面

不仅可以很方便的编写用例,同时也可以很方便的管理测试用例集;
最重要的是可以直接根据测试用例生成自动化代码样例,
并且能在自动化代码与测试用例可以自由的相互跳转:

详细的测试报告

你几乎可以不用定义任何测试报告,运行完项目自动生成测试报告;
同时支持多种测试报告模板供选择;测试报告支持导出PDF,邮件发送常用功能:

屏幕录制功能

Web自动化过程中,只需要在运行配置中开启屏幕录制功能,项目运行中即可自动录制屏幕:

可以与其它框架优雅的结合起来

CukeTest可以与selenium,appium这些常用的测试框架结合起来一起使用。也可以使用nodejs流行的第三方HTTP库函数进行API自动化测试。
所以CukeTest在web,手机端,API的自动化都可以进行。

可以很方便持续集成

CukeTest支持命令行方式运行脚本,所以可以与所有CI工具一起使用。

xCukeTest可以让团队更加敏捷

使用行为驱动开发,能够开发出大家都看得懂的测试脚本,不管懂不懂编程。而且。使用自然语言将我们的测试用例与自动化代码结合,可以在团队中以用例设计为测试准则,减少团队直接的沟通成本,同时又可以让团队中更多的成员参与进来。

几乎不用重新造轮子,测试报告,屏幕录像这些操作都给我们提供了,我们只需要关注我们的业务,实现对应的代码既可。最重要的一点,CukeTest还是对所有开源社区和个人使用者是免费的。是的,免费!

请记住CukeTest只是一个编辑工具、帮助你提高你在Node.js上的开发效率。你开发的自动化脚本仍旧是基于开源框架的,这意味着你仍旧可以不用这个编辑工具,也能运行你的脚本,保持了脚本的独立性。CukeTest可以在cuketest.com网站免费下载,或是在Windows10应用商店免费安装。

声明

转载请注明出处:https://liyinchigithub.github.io/ 谢谢您的配合

mockjs

开始 & 安装

Node (CommonJS)

安装

npm install mockjs

1
2
3
4
5
6
7
8
9
10
11
// 使用 Mock
var Mock = require('mockjs')
var data = Mock.mock({
// 属性 list 的值是一个数组,其中含有 1 到 10 个元素
'list|1-10': [{
// 属性 id 是一个自增数,起始值为 1,每次增 1
'id|+1': 1
}]
})
// 输出结果
console.log(JSON.stringify(data, null, 4))

Bower

安装

1
2
npm install -g bower
bower install --save mockjs

<script type="text/javascript" src="./bower_components/mockjs/dist/mock.js"></script>

RequireJS (AMD)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 配置 Mock 路径
require.config({
paths: {
mock: 'http://mockjs.com/dist/mock'
}
})
// 加载 Mock
require(['mock'], function(Mock){
// 使用 Mock
var data = Mock.mock({
'list|1-10': [{
'id|+1': 1
}]
})
// 输出结果
document.body.innerHTML +=
'<pre>' +
JSON.stringify(data, null, 4) +
'</pre>'
})

// ==>

1
2
3
4
5
6
7
8
9
10
11
12
13
14

{
"list": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
}
]
}

JSFiddle

Sea.js (CMD)

因为 Sea.js 社区尚未提供 webpack 插件,所以 Mock.js 暂不完整支持通过 Sea.js 加载。

一种变通的方式是,依然通过 Sea.js 配置和加载 Mock.js,然后访问全局变量 Mock。

1
2
3
4
5
6
// 配置 Mock 路径
seajs.config({
alias: {
mock: 'http://mockjs.com/dist/mock.js'
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
// 加载 Mock
seajs.use('mock', function(__PLACEHOLDER) {
// 使用 Mock(全局变量)
var data = Mock.mock({
'list|1-10': [{
'id|+1': 1
}]
});
document.body.innerHTML +=
'<pre>' +
JSON.stringify(data, null, 4) +
'</pre>'
})

JSFiddle

Random CLI

1
2
3
4
5
6
7
8
9
10

# 全局安装
$ npm install mockjs -g

# 执行
$ random url
# => http://rmcpx.org/funzwc

# 帮助
random -h

声明

转载请注明出处:https://liyinchigithub.github.io/ 谢谢您的配合

如何编写README.md?

最近对它的README.md文件颇为感兴趣。

帮助更多的还不会编写README文件的同学们。

README文件后缀名为md

md是markdown的缩写,markdown是一种编辑博客的语言。用惯了可视化的博客编辑器(比如CSDN博客,囧),这种编程式的博客编辑方案着实让人眼前一亮。不过GitHub支持的语法在标准markdown语法的基础上做了修改,称为Github Flavored Markdown,简称GFM。可不是GFW呀偷笑。

开始编辑README

打开你的GitHub的某个项目,我们可以直接在线编辑你的README文件,如果你已经有了这个文件,则在文件目录中直接点击它,如果你还没有这个文件那么点击项目名称右边的一个按钮,来添加新文件:

然后你就打开了编辑页面,编辑区的左上角有填写文件名的区域,注意加上后缀.md

如果你本来就有这个文件要重新编辑它的话,那么在点击了文件目录中的该文件后,在上方有工具栏,选择Edit

然后滚动屏幕到下面,如果是新文件会有一个Commit new file的按钮,若没有内容是不能点击的。如果是旧文件重修编辑,那么这个按钮显示的是 Commit changes

先随便写的东西把这个新文件提交,然后再点击 Edit 重新打开它。你会发现编辑区左上角有了变化。

默认选中Code,即我们的编辑模式。若点击 Preview(预览)就能实时显示当前的显示效果了。

好了,下面正式开始编辑这个文件

大标题

规范的README文件开头都写上一个标题,这被称为大标题。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

大标题

在文本下面加上 等于号 = ,那么上方的文本就变成了大标题。等于号的个数无限制,但一定要大于0个哦。。
比大标题低一级的是中标题,也就是显示出来比大标题小点。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

中标题

在文本下面加上 下划线 - ,那么上方的文本就变成了中标题,同样的 下划线个数无限制。

除此之外,你也会发现大,中标题下面都有一条横线,没错这就是 = 和 - 的显示结果。

如果你只输入了等于号=,但其上方无文字,那么就只会显示一条直线。如果上方有了文字,但你又只想显示一条横线,而不想把上方的文字转义成大标题的话,那么你就要在等于号=和文字直接补一个空行。

补空行:是很常用的用法,当你不想上下两个不同的布局方式交错到一起的时候,就要在两种布局之间补一个空行。

如果你只输入了短横线(减号)-,其上方无文字,那么要显示直线,必须要写三个减号以上。不过与等于号的显示效果不同,它显示出来时虚线而不是实线。同减号作用相同的还有星号*和下划线_,同样的这两者符号也要写三个以上才能显示一条虚横线。

除此以外,关于标题还有等级表示法,分为六个等级,显示的文本大小依次减小。不同等级之间是以井号 # 的个数来标识的。一级标题有一个 #,二级标题有两个# ,以此类推。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

#一级标题

##二级标题

###三级标题

####四级标题

#####五级标题

######六级标题
注意井号#和标题名称要并排写作一行,显示效果如图:

实际上,前文所述的大标题和中标题是分别和一级标题和二级标题对应的。即大标题大小和一级标题相同,中标题大小和二级标题相同。

显示文本

普通文本
直接输入的文字就是普通文本。需要注意的是要换行的时候不能直接通过回车来换行,需要使用
(或者
)。也就是html里面的标签。事实上,markdown支持一些html标签,你可以试试。当然如果你完全使用html来写的话,就丧失意义了,毕竟markdown并非专门做前端的,然而仅实现一般效果的话,它会比html写起来要简洁得多得多啦。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

这是一段普通的文本,
直接回车不能换行,

要使用\

注意第三行的
前加了反斜杠 \ 。目的就是像其他语言那样实现转义,也就是 < 的转义。
效果如图:

此外,要显示一个超链接的话,就直接输入这个链接的URL就好了。显示出来会自动变成可链接的形式的。

显示空格的小Tip
默认的文本行首空格都会被忽略的,但是如果你想用空格来排一下版的话怎么办呢,有个小技巧,那就是把你的输入法由半角改成全角就OK啦。
单行文本
使用两个Tab符实现单行文本。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

Hello,大家好,我是方块银。
注意前面有两个Tab。在GitHub上单行文本显示效果如图:

多行文本
多行文本和单行文本异曲同工,只要在每行行首加两个Tab

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

欢迎到访
很高兴见到您
祝您,早上好,中午好,下午好,晚安

部分文字的高亮
如果你想使一段话中部分文字高亮显示,来起到突出强调的作用,那么可以把它用 包围起来。注意这不是单引号,而是Tab上方,数字1左边的按键(注意使用英文输入法)。

Thank You . Please Call Me Coder

文字超链接

给一段文字加入超链接的格式是这样的 要显示的文字 。比如:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

我的博客
显示效果:

你还可以给他加上一个鼠标悬停显示的文本。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

我的博客
即在URL之后 用双引号括起来一个字符串。同样要注意这里是英文双引号。

插入符号
圆点符
这是一个圆点符
这也是一个圆点符
上面这段的圆点是CSDN博客编辑器里面的符号列表。写文章在列出条目时经常用到。在GitHub的markdown语法里也支持使用圆点符。编辑的时候使用的是星号 *

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

  • 昵称:liyinchi
  • 别名:方块银
  • 英文名:Jack li
    要注意的是星号* 后面要有一个空格。否则显示为普通星号。上文的显示效果如图:

此外还有二级圆点和三级圆点。就是多加一个Tab。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

  • 编程语言
    • 脚本语言
      • Python
        第二行一个Tab,第三行两个Tab。这样用来表示层级结构就更清晰了吧,看效果:

如果你觉得三级的结构还不够表达清楚的话,我们可以试着换一种形式,请看字符包围

缩进
缩进的含义是很容易理解的。。

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

数据结构

二叉树

平衡二叉树

满二叉树
显示效果:

当然比这个更一般的用法是这样。常常能在书籍里面看到的效果,比如引用别人的文章。直接看效果。

具体这个“缩进”的用法。大家自己摸索吧。

插入图片

来源于网络的图片

网上有很多README插入图片的教程了,经我自己多次测试呢,发现可以使用的最简单,最基本的语法是:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片


即 叹号! + 方括号[ ] + 括号( ) 其中叹号里是图片的URL。

如果不加叹号! ,就会变成普通文本baidu了。

在方括号里可以加入一些 标识性的信息,比如

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

baidu
这个方括号里的baidu并不会对图像显示造成任何改动,如果你想达到鼠标悬停显示提示信息,那么可以仿照前面介绍的文本中的方法,就是这样:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

baidu
在URL后面,加一个双引号包围的字符串,显示效果如图:

GitHub仓库里的图片
有时候我们想显示一个GitHub仓库(或者说项目)里的图片而不是一张其他来源网络图片,因为其他来源的URL很可能会失效。那么如何显示一个GitHub项目里的图片呢?

其实与上面的格式基本一致的,所不同的就是括号里的URL该怎么写。

https://github.com/ 你的用户名 / 你的项目名 / raw / 分支名 / 存放图片的文件夹 / 该文件夹下的图片

这样一目了然了吧。比如:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

给图片加上超链接
如果你想使图片带有超链接的功能,即点击一个图片进入一个指定的网页。那么可以这样写:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片

![baidu]
[baidu]:http://www.baidu.com/img/bdlogo.gif “百度Logo”
这两句和前面的写法差异较大,但是也极易模仿着写出,就不过多介绍了。只需注意上下文中的 baidu 是你自己起的标识的名称,可以随意,但是一定要保证上下两行的 标识 是一致的。
这样就能实现 点击图片进入网页的功能了。

插入代码片段
我们需要在代码的上一行和下一行用` 标记。

``` 之后加上你的编程语言即可(忽略大小写)。c++语言可以写成c++也可以是cpp。看代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112



实际显示效果



[题外话]在GitHub上用Gist写日记吧
看了这么多markdown的语法,你一定不满足于仅仅写一个README文件了,开始跃跃欲试想实际用markdown语法来编写博客或文章了吧。的确,网上也有依托或者支持markdown语法的博客。但是呢,更方便的是,你可以借助GitHub本身就有的一个功能——Gist。

Gist是以文件为单位的,不是以项目为单位的。而且与普通的GitHub上建的仓库不同,Gist是private的哦。普通的项目默认都是public的,要想弄成private貌似还要交钱的样子。既然是private那么用来写写日记,是极好的。

GitHub网页的顶部有:



点进去:



这就是你可以编辑的私有文件,它不仅支持Text文本,还支持各种编程语言呢!当然也包括markdown。输入文件名:



最后保存,选中 Create Secret Gist 就是私有的喽。



-----------下面是一个README.md例子


README
====
该文件用来测试和展示书写README的各种markdown语法。GitHub的markdown语法在标准的markdown语法基础上做了扩充,称之为`GitHub Flavored Markdown`。简称`GFM`,GFM在GitHub上有广泛应用,除了README文件外,issues和wiki均支持markdown语法。

****

|Author|JackLi|
|---|---
|E-mail|liyinchi@qq.com


****
## 目录
* [横线](#横线)
* [标题](#标题)
* [文本](#文本)
* 普通文本
* 单行文本
* 多行文本
* 文字高亮
* 换行
* 斜体
* 粗体
* 删除线
* [图片](#图片)
* 来源于网络的图片
* GitHub仓库中的图片
* [链接](#链接)
* 文字超链接
* 链接外部URL
* 链接本仓库里的URL
* 锚点
* [图片链接](#图片链接)
* [列表](#列表)
* 无序列表
* 有序列表
* 复选框列表
* [块引用](#块引用)
* [代码高亮](#代码高亮)
* [表格](#表格)
* [表情](#表情)
* [diff语法](#diff语法)

### 横线
-----------
***、---、___可以显示横线效果

***
---
___



标题
====

# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题


文本
====
### 普通文本
这是一段普通的文本
### 单行文本
Hello,大家好,我是Jack li。
在一行开头加入1个Tab或者4个空格。
### 文本块
#### 语法1
在连续几行的文本开头加入1个Tab或者4个空格。

欢迎到访
很高兴见到您
祝您,早上好,中午好,下午好,晚安

#### 语法2
使用一对各三个的反引号:

欢迎到访
我是JavaScript、Java码农
你可以在github搜索【liyinchi】找到我

1
2
3
4
该语法也可以实现代码高亮,见[代码高亮](#代码高亮)
### 文字高亮
文字高亮功能能使行内部分文字高亮,使用一对反引号。
语法:

linux 网络编程 socket epoll

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
效果:`linux` `网络编程` `socket` `epoll`

也适合做一篇文章的tag
#### 换行
直接回车不能换行,
可以在上一行文本后面补两个空格,
这样下一行的文本就换行了。

或者就是在两行文本直接加一个空行。

也能实现换行效果,不过这个行间距有点大。
#### 斜体、粗体、删除线

|语法|效果|
|----|-----|
|`*斜体1*`|*斜体1*|
|`_斜体2_`| _斜体2_|
|`**粗体1**`|**粗体1**|
|`__粗体2__`|__粗体2__|
|`这是一个 ~~删除线~~`|这是一个 ~~删除线~~|
|`***斜粗体1***`|***斜粗体1***|
|`___斜粗体2___`|___斜粗体2___|
|`***~~斜粗体删除线1~~***`|***~~斜粗体删除线1~~***|
|`~~***斜粗体删除线2***~~`|~~***斜粗体删除线2***~~|

斜体、粗体、删除线可混合使用

图片
====
基本格式:

alt

1
2
3
4
5
alt和title即对应HTML中的alt和title属性(都可省略):
- alt表示图片显示失败时的替换文本
- title表示鼠标悬停在图片时的显示文本(注意这里要加引号)

URL即图片的url地址,如果引用本仓库中的图片,直接使用**相对路径**就可了,如果引用其他github仓库中的图片要注意格式,即:`仓库地址/raw/分支名/图片路径`,如:

https://github.com/xxx/ImageCache/raw/master/Logo/foryou.gif

1
2
3
4
5
6
7
8

|#|语法|效果|
|---|---|----
|1|`![baidu](http://www.baidu.com/img/bdlogo.gif "百度logo")`|![baidu](http://www.baidu.com/img/bdlogo.gif "百度logo")
|2|`![][foryou]`|![][foryou]

注意例2的写法使用了**URL标识符**的形式,在[链接](#链接)一节有介绍。
>在文末有foryou的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

链接
====
### 链接外部URL

|#|语法|效果|
|---|----|-----|
|1|`[我的博客](https://liyinchigithub.github.io/ "悬停显示")`|[我的博客](https://liyinchigithub.github.io/ "悬停显示")|

语法2由两部分组成:
- 第一部分使用两个中括号,[ ]里的标识符(本例中zhihu),可以是数字,字母等的组合,标识符上下对应就行了(**姑且称之为URL标识符**)
- 第二部分标记实际URL。

>使用URL标识符能达到复用的目的,一般把全文所有的URL标识符统一放在文章末尾,这样看起来比较干净。
>>URL标识符是我起的名字,不知道是否准确。囧。。

### 链接本仓库里的URL

|语法|效果|
|----|-----|
|`[我的简介](/example/profile.md)`|[我的简介](/example/profile.md)|
|`[example](./example)`|[example](./example)|

### 图片链接
给图片加链接的本质是混合图片显示语法和普通的链接语法。普通的链接中[ ]内部是链接要显示的文本,而图片链接[ ]里面则是要显示的图片。
直接混合两种语法当然可以,但是十分啰嗦,为此我们可以使用URL标识符的形式。

|#|语法|效果|
|---|----|:---:|
|1|`[![weibo-logo]](http://weibo.com)`|[![weibo-logo]](http://weibo.com/)|
|2|`[![](/img/zhihu.png "我的知乎,欢迎关注")][zhihu]`|[![](/img/zhihu.png "我的知乎,欢迎关注")][zhihu]|
|3|`[![csdn-logo]][csdn]`|[![csdn-logo]][csdn]|

因为图片本身和链接本身都支持URL标识符的形式,所以图片链接也可以很简洁(见例3)。
注意,此时鼠标悬停时显示的文字是图片的title,而非链接本身的title了。
> 本文URL标识符都放置于文末

### 锚点
其实呢,每一个标题都是一个锚点,和HTML的锚点(`#`)类似,比如我们

|语法|效果|
|---|---|
|`[回到顶部](#readme)`|[回到顶部](#readme)|

不过要注意,标题中的英文字母都被转化为**小写字母**了。
> 以前GitHub对中文支持的不好,所以中文标题不能正确识别为锚点,但是现在已经没问题啦!

## 列表
### 无序列表
#### 语法
  • 昵称:liyinchi
  • 别名:方块银
  • 英文名:Jack Li

    1
    2
    3
    4
    5
    6
    7
    #### 效果
    * 昵称:liyinchi
    - 别名:方块银
    * 英文名:Jack Li

    ### 多级无序列表
    #### 语法
  • 编程语言

    • 脚本语言
      • JAVA
        1
        2
        3
        4
        5
        6
        7
        8
        #### 效果
        * 编程语言
        * 脚本语言
        * JAVA

        ### 一级有序列表
        #### 语法
        就是在数字后面加一个点,再加一个空格。不过看起来起来可能不够明显。

面向对象的三个基本特征:

  1. 封装
  2. 继承
  3. 多态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    #### 效果
    面向对象的三个基本特征:

    1. 封装
    2. 继承
    3. 多态


    ### 多级有序列表
    和无序列表一样,有序列表也有多级结构。
    #### 语法
  4. 这是一级的有序列表,数字1还是1

    1. 这是二级的有序列表,阿拉伯数字在显示的时候变成了罗马数字
      1. 这是三级的有序列表,数字在显示的时候变成了英文字母
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10

        #### 效果

        1. 这是一级的有序列表,数字1还是1
        1. 这是二级的有序列表,阿拉伯数字在显示的时候变成了罗马数字
        1. 这是三级的有序列表,数字在显示的时候变成了英文字母


        ### 复选框列表
        #### 语法
  • 需求分析
  • 系统设计
  • 详细设计
  • 编码
  • 测试
  • 交付
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #### 效果

    - [x] 需求分析
    - [x] 系统设计
    - [x] 详细设计
    - [ ] 编码
    - [ ] 测试
    - [ ] 交付

    您可以使用这个功能来标注某个项目各项任务的完成情况。
    > Tip:
    >> 在GitHub的**issue**中使用该语法是可以实时点击复选框来勾选或解除勾选的,而无需修改issue原文。

    ## 块引用

    ### 常用于引用文本
    #### 文本摘自《深入理解计算机系统》P27
     令人吃惊的是,在哪种字节顺序是合适的这个问题上,人们表现得非常情绪化。实际上术语“little endian”(小端)和“big endian”(大端)出自Jonathan Swift的《格利佛游记》一书,其中交战的两个派别无法就应该从哪一端打开一个半熟的鸡蛋达成一致。因此,争论沦为关于社会政治的争论。只要选择了一种规则并且始终如一的坚持,其实对于哪种字节排序的选择都是任意的。
    > **“端”(endian)的起源**
    以下是Jonathan Swift在1726年关于大小端之争历史的描述:
    “……下面我要告诉你的是,Lilliput和Blefuscu这两大强国在过去36个月里一直在苦战。战争开始是由于以下的原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端,可是当今的皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋时碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破较小的一端,违令者重罚。”

    ### 块引用有多级结构
    #### 语法

数据结构

二叉树

平衡二叉树

满二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#### 效果
> 数据结构
>> 树
>>> 二叉树
>>>> 平衡二叉树
>>>>> 满二叉树

代码高亮
====

### 语法
在三个反引号后面加上编程语言的名字,另起一行开始写代码,最后一行再加上三个反引号。

### 效果

public static void main(String[]args){} //Java

1
2
```c
int main(int argc, char *argv[]) //C

1
echo "hello GitHub" #Bash
1
document.getElementById("myH1").innerHTML="Welcome to my Homepage"; //javascipt
1
string &operator+(const string& A,const string& B) //cpp

表格

表头1 表头2
表格单元 表格单元
表格单元 表格单元
表头1 表头2
表格单元 表格单元
表格单元 表格单元

对齐

表格可以指定对齐方式

左对齐 居中 右对齐
col 3 is some wordy text $1600
col 2 is centered $12
zebra stripes are neat $1

混合其他语法

表格单元中的内容可以和其他大多数GFM语法配合使用,如:

使用普通文本的删除线,斜体等效果

名字 描述
Help Display the help window.
Close Closes a window

表格中嵌入图片(链接)

其实前面介绍图片显示、图片链接的时候为了清晰就是放在在表格中显示的。

图片 描述
![baidu][baidu-logo] 百度

表情

Github的Markdown语法支持添加emoji表情,输入不同的符号码(两个冒号包围的字符)可以显示出不同的表情。

比如:blush:,可以显示:blush:。

具体每一个表情的符号码,可以查询GitHub的官方网页http://www.emoji-cheat-sheet.com

但是这个网页每次都打开奇慢。。所以我整理到了本repo中,大家可以直接在此查看emoji

diff语法

版本控制的系统中都少不了diff的功能,即展示一个文件内容的增加与删除。
GFM中可以显示的展示diff效果。使用绿色表示新增,红色表示删除。

语法

其语法与代码高亮类似,只是在三个反引号后面写diff,
并且其内容中,以 +开头表示新增,-开头表示删除。

效果

1
2
+ 鸟宿池边树,僧敲月下门
- 鸟宿池边树,僧推月下门

声明

转载请注明出处:https://liyinchigithub.github.io/ 谢谢您的配合