整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

「ApiPost」断言详解(6)-本章需要(Java

「ApiPost」断言详解(6)-本章需要(JavaScript)编程基础

用流程

1. 定义测试用例

2. 验证测试用例

以示例接口 新闻列表为例,新闻列表返回响应数据如下:

```javascript
{
"code": 10000,
"msg": "success",
"data": {
"cur_page": "1",
"last_page": 2,
"page_size": "20",
"total": 30,
"list": [
{
"id": 3,
"title": "前后仅用了4分钟,16枚洲际导弹应声而出,美航母也不敢轻举妄动",
"author": "烽火杂志",
"url": "https://open.apipost.cn/",
"content": "世界上哪个国家可与美军抗衡?国际社会上关于这一问题的答案千奇百怪,但有一个国家用行动让美军闭嘴,短短4分钟连续发射16枚洲际导弹,场面十分壮观,让西方国家畏惧不已,即便是美航母也不敢轻举妄动。"
}
]
}
}
```

一、定义测试用例

定义入口在后执行脚本里;

特别注意:==每个测试用例是一行,不能换行。==

通用和常用的测试用例定义如下:

```javascript
apt.assert('response.raw.responseText=="test"');
apt.assert('response.raw.status==200');
apt.assert('response.raw.type=="json"');
apt.assert('response.raw.responseTime>=100');
apt.assert('response.json.errcode==1');
apt.assert('response.json.errcode!=1');
apt.assert('response.json.errcode>=1');
apt.assert('response.json.errcode==null');
apt.assert('response.json.errcode!=null');
apt.assert('response.headers["server"]=="nginx"');
apt.assert('response.headers["content-encoding"]=="gzip"');
apt.globals.set("key", "value");
apt.globals.get("key");
apt.globals.delete("key");
apt.globals.clear();
apt.variables.set("key", "value");
apt.variables.get("key");
apt.variables.delete("key");
apt.variables.clear();
$.ajax({
"url":"https://echo.apipost.cn/token.php",
"method":"POST",
"async":false,
"content-type":"appicateion-json",
"data":JSON.stringify({
"email":"admin@admin.com",
"password":"密码"
}),
"success":function(response){
response=typeof response=="object" ? response : JSON.parse(response);
console.log(response);
apt.variables.set("token", response.token);
}
});
```

针对新闻列表这个接口测试用例定义如下:

```javascript
apt.assert('response.raw.status==200');
apt.assert('response.raw.type=="json"');
apt.assert('response.raw.responseTime>=100');
apt.assert('response.json.code==10000');
apt.assert('response.json.msg=="success"');
apt.assert('response.raw.responseText.indexOf("data") > -1'); // 检查响应文本是否含有data字符串
apt.assert('response.json.hasOwnProperty("data")'); // 检测返回json对象的是否含有data字段
apt.assert('response.json.data.cur_page=="1"');
apt.assert('response.json.data.last_page==2');
apt.assert('response.json.data.page_size=="20"');
apt.assert('response.json.data.total==30');
```

下图为运行效果图

二、验证测试用例

绿色表示测试通过,红色表示测试不通过

再加一个明显不通过的定义:apt.assert('response.raw.responseText=="test"');

```javascript
apt.assert('response.raw.responseText=="test"');
apt.assert('response.raw.status==200');
apt.assert('response.raw.type=="json"');
apt.assert('response.raw.responseTime>=100');
apt.assert('response.json.code==10000');
apt.assert('response.json.msg=="success"');
apt.assert('response.raw.responseText.indexOf("data") > -1'); // 检查响应文本是否含有data字符串
apt.assert('response.json.hasOwnProperty("data")'); // 检测返回json对象的是否含有data字段
apt.assert('response.json.data.cur_page=="1"');
apt.assert('response.json.data.last_page==2');
apt.assert('response.json.data.page_size=="20"');
apt.assert('response.json.data.total==30');
```

结果如图:

三、集合(list)验证(官网里并没有这个示例,笔者是结合js语法特点然后一点点调试出来的,如有不足请谅解)

定义如下:

```javascript
//验证集合list测试用例定义;
// 笔者暂时还没有找到添加断言业务描述的参数方法,一般断言有断言描述和断言表达式。但这个语法上好像不支持。
// 后期如果找到一并补充上
if(response.json.hasOwnProperty("data")){
// apt.assert('response.raw.responseText=="test"');
if(response.json.data.hasOwnProperty("list")
&& response.json.data.list.length>0){
// apt.assert('response.raw.responseText=="test"');
for(var i=0;i<response.json.data.list.length;i++){
apt.assert(true,"i="+i);
var item=response.json.data.list[i];
response.json.data.item=item;
apt.assert('response.json.data.item.hasOwnProperty("id")');
apt.assert('response.json.data.item.hasOwnProperty("title")');
apt.assert('response.json.data.item.hasOwnProperty("author")');
apt.assert('response.json.data.item.hasOwnProperty("url")');
apt.assert('response.json.data.item.hasOwnProperty("content")');
}
}
}
```

结果见下图:

笔者暂时还没有找到添加断言业务描述的参数方法,一般断言有断言描述和断言表达式。但这个语法上好像不支持。后期如果找到一并补充上

四、断言扩展体会

示例接口由于是动态环境,所以数据值会发生变化,不利于进行原始数据与后期接口获取的数据进行数据文件上的验证。

如不理解没有关系,这个属于业务数据驱动接口测试的一种测试理念。一般在大型且各种资源比较充沛的团队才进行这样的从服务环境、数据库、业务数据添加,修改,删除等一系列流程上完全被定义可预测且能验证的整体可测的测试设计。

不过笔者搞开发十多年也没有见过这样的大手笔。可能大厂有吧!一般几十刚过百人的研发团队就算了。没那必要性。

不过如果是支撑大流量且需要在高速奔跑火车上换换轮子的极端情况,搞这么一个十个人左右的小的数据驱动一切可测设计的测试团队还是有比较可观的收益的。这样可评估线上生产环境的风险范围以及当前研发团队的研发质量和风险意识。

期待扩展出使用json等格式文件进行数据断言的版本

五、番外

搞开发这些年见过很多给开发打绩效的方案:

比如:按代码量的,按工时的,按编码时长的,按提交数量的等等方式。只能说有比没有好吧!在表面搞搞人力绩效还是很能让老板满意的,于是各种加班996,007就出现了。

其实开发质量是可以从API接口测试里体现出来的能兼容的场景参数越多,服务越稳定。技术当然会比较好。当然笔者的观点估计不好理解和接受。这种用单元测试来衡量开发质量的还得是开发自己人来搞。不过接口工具的出现到提供了非开发人员来量化开发人员质量,也许是不错的方式。


处理网页数据时,我们经常需要从HTML中提取日期信息。日期格式多样,从HTML文档中准确地提取并验证这些信息是一项挑战。本文将详细介绍如何使用正则表达式从HTML中提取日期,并用Python代码进行有效性验证。

一、正则表达式基础

概念:

正则表达式是用于文本搜索和替换的强大工具,它能够描述复杂的模式。

基本语法元素:

字符集:[0-9]匹配任意数字,[a-zA-Z]匹配任意字母。

量词:*(零次或多次)、+(一次或多次)等。

特殊字符:.匹配任意单个字符,\d匹配任意数字。

分组:(19|20)\d\d匹配以19或20开头的年份。

二、从HTML中提取日期

HTML结构分析:

检查网页源代码,找到包含日期的标签或属性。

日期可能以不同格式存在,比如文本形式或属性值。

构建正则表达式:

针对YYYY-MM-DD、DD-MM-YYYY、MM/DD/YYYY等格式编写正则表达式。

考虑HTML文档结构的差异,调整正则表达式以提高匹配的准确性。

三、验证日期的有效性

日期格式验证:

确保提取的字符串符合日期格式,但还需要进一步验证日期的实际有效性。

正则表达式初步验证:

使用正则表达式确保日期组件在合理范围内,如月份应在01至12之间。

编程验证日期有效性:

使用Python的datetime模块进行进一步验证。

考虑特殊情况,如闰年和每月的实际天数。

四、实际案例分析

案例演示:

选取具有代表性的网页HTML样本,标识其中的日期信息。

编写适用的正则表达式来匹配这些日期。

代码实现:

使用Python演示如何应用正则表达式提取日期。

展示如何使用datetime模块验证日期有效性。

五、总结与展望

总结:

正则表达式是提取HTML中日期信息的有效工具,但还需通过编程验证其有效性。

未来应用:

探讨正则表达式在数据分析、日志处理等领域的应用。

小结

本文提供了一个全面的指南,说明了如何使用正则表达式从HTML文档中提取日期,并通过Python代码进行验证。这些技能对于数据抓取和文本处理领域非常重要。

Python 代码示例

1. 正则表达式提取日期

python

import re

from datetime import datetime

# 示例HTML内容

html_content="""

<p>发表日期:2020-12-15</p>

<p>更新日期:2021/01/20</p>

<p>活动日期:31-01-2022</p>

"""

# 正则表达式匹配不同的日期格式

date_patterns=[

r'\d{4}-\d{2}-\d{2}', # YYYY-MM-DD

r'\d{2}/\d{2}/\d{4}', # DD/MM/YYYY

r'\d{2}-\d{2}-\d{4}' # DD-MM-YYYY

]

# 提取日期

extracted_dates=[]

for pattern in date_patterns:

matches=re.findall(pattern, html_content)

extracted_dates.extend(matches)

print("Extracted Dates:", extracted_dates)

2. 验证日期有效性

python

# 验证日期有效性

def validate_date(date_str):

for fmt in ("%Y-%m-%d", "%d/%m/%Y", "%d-%m-%Y"):

try:

datetime.strptime(date_str, fmt)

return True

except ValueError:

continue

return False

# 验证提取的日期

valid_dates=[date for date in extracted_dates if validate_date(date)]

print("Valid Dates:", valid_dates)

在这个例子中,我们首先使用正则表达式从HTML内容中提取日期,然后使用Python的datetime模块验证这些日期的有效性。这种方法适用于不同格式的日期,并能有效地识别和排除无效日期。

validator.js是一个Github上专门针对字符串校验所建立的一个工具库,validator.js包含了大量实用的字符串校验和清洗方法,并且支持在Node环境和浏览器环境使用,非常实用。



Github

https://github.com/validatorjs/validator.js

安装实用

包管理方式安装

npm install validator
//或者
yarn add validator

可以在各种开发场景下使用

  • 不在es6环境下的模块化
var validator=require('validator');

validator.isEmail('foo@bar.com'); //=> true
  • es6的模块化

可以一次性全部导入

import validator from 'validator';

也可以针对不同方法单独引入,比如我们只需要导入验证邮箱的方法

import isEmail from 'validator/lib/isEmail';

或者Tree-shakeable ES imports导入

import isEmail from 'validator/es/lib/isEmail';
  • 浏览器直接使用
<script type="text/javascript" src="validator.min.js"></script>
<script type="text/javascript">
  validator.isEmail('foo@bar.com'); //=> true
</script>

方法列表

方法非常丰富,可以根据需要进行使用,建议先看一下Github上中每个方法的含义和使用方式。

import toDate from './lib/toDate';
import toFloat from './lib/toFloat';
import toInt from './lib/toInt';
import toBoolean from './lib/toBoolean';
import equals from './lib/equals';
import contains from './lib/contains';
import matches from './lib/matches';

import isEmail from './lib/isEmail';
import isURL from './lib/isURL';
import isMACAddress from './lib/isMACAddress';
import isIP from './lib/isIP';
import isIPRange from './lib/isIPRange';
import isFQDN from './lib/isFQDN';
import isDate from './lib/isDate';

import isBoolean from './lib/isBoolean';
import isLocale from './lib/isLocale';

import isAlpha, { locales as isAlphaLocales } from './lib/isAlpha';
import isAlphanumeric, { locales as isAlphanumericLocales } from './lib/isAlphanumeric';
import isNumeric from './lib/isNumeric';
import isPassportNumber from './lib/isPassportNumber';
import isPort from './lib/isPort';
import isLowercase from './lib/isLowercase';
import isUppercase from './lib/isUppercase';

import isIMEI from './lib/isIMEI';

import isAscii from './lib/isAscii';
import isFullWidth from './lib/isFullWidth';
import isHalfWidth from './lib/isHalfWidth';
import isVariableWidth from './lib/isVariableWidth';
import isMultibyte from './lib/isMultibyte';
import isSemVer from './lib/isSemVer';
import isSurrogatePair from './lib/isSurrogatePair';

import isInt from './lib/isInt';
import isFloat, { locales as isFloatLocales } from './lib/isFloat';
import isDecimal from './lib/isDecimal';
import isHexadecimal from './lib/isHexadecimal';
import isOctal from './lib/isOctal';
import isDivisibleBy from './lib/isDivisibleBy';

import isHexColor from './lib/isHexColor';
import isRgbColor from './lib/isRgbColor';
import isHSL from './lib/isHSL';

import isISRC from './lib/isISRC';

import isIBAN, { locales as ibanLocales } from './lib/isIBAN';
import isBIC from './lib/isBIC';

import isMD5 from './lib/isMD5';
import isHash from './lib/isHash';
import isJWT from './lib/isJWT';

import isJSON from './lib/isJSON';
import isEmpty from './lib/isEmpty';

import isLength from './lib/isLength';
import isByteLength from './lib/isByteLength';

import isUUID from './lib/isUUID';
import isMongoId from './lib/isMongoId';

import isAfter from './lib/isAfter';
import isBefore from './lib/isBefore';

import isIn from './lib/isIn';

import isCreditCard from './lib/isCreditCard';
import isIdentityCard from './lib/isIdentityCard';

import isEAN from './lib/isEAN';
import isISIN from './lib/isISIN';
import isISBN from './lib/isISBN';
import isISSN from './lib/isISSN';
import isTaxID from './lib/isTaxID';

import isMobilePhone, { locales as isMobilePhoneLocales } from './lib/isMobilePhone';

import isEthereumAddress from './lib/isEthereumAddress';

import isCurrency from './lib/isCurrency';

import isBtcAddress from './lib/isBtcAddress';

import isISO8601 from './lib/isISO8601';
import isRFC3339 from './lib/isRFC3339';
import isISO31661Alpha2 from './lib/isISO31661Alpha2';
import isISO31661Alpha3 from './lib/isISO31661Alpha3';
import isISO4217 from './lib/isISO4217';

import isBase32 from './lib/isBase32';
import isBase58 from './lib/isBase58';
import isBase64 from './lib/isBase64';
import isDataURI from './lib/isDataURI';
import isMagnetURI from './lib/isMagnetURI';

import isMimeType from './lib/isMimeType';

import isLatLong from './lib/isLatLong';
import isPostalCode, { locales as isPostalCodeLocales } from './lib/isPostalCode';

import ltrim from './lib/ltrim';
import rtrim from './lib/rtrim';
import trim from './lib/trim';
import escape from './lib/escape';
import unescape from './lib/unescape';
import stripLow from './lib/stripLow';
import whitelist from './lib/whitelist';
import blacklist from './lib/blacklist';
import isWhitelisted from './lib/isWhitelisted';

import normalizeEmail from './lib/normalizeEmail';

import isSlug from './lib/isSlug';
import isLicensePlate from './lib/isLicensePlate';
import isStrongPassword from './lib/isStrongPassword';

import isVAT from './lib/isVAT';

总结

validator.js是一个非常值得学习的工具库,不仅是使用它,也可以用它来学习一些JavaScript的基础知识,学习其中各类方法的写法,也可以巩固JavaScript的基础知识!