不想当将军的小兵,不是好的小兵;不想做开发的测试,不是好的测试;
不管你信不信,我是信了...
一直以来,内心总有些迷茫的时候,迷茫的是作为测试既然要学那么多编程,为什么不直接去干开发呢?
看了这句话,才发现自己钻进了牛角尖,没有站在更高的高度来思考测试这个岗位,而仅仅是作为一个测试员,或者说是抱着急功近利的心态在想问题,从而忽略了测试的本质。
测试的本质是尽可能的发现软件的缺陷,更高级的应该是用更少的时间,更少的人员来找出更多的缺陷。那么不管更好的测试流程,更高效的测试方法,更好的测试工具,这些都应该是我们追求的东西。
流程,方法,工具,这三者中我认为更重要的应该是方法,最难提升的也是方法。
编码啊工具之类的可以用到哪些提升哪些,
说到底,不管是开发中的编码,还是测试中的编码,都是很初级的工作,都不是这个职业链中的高端,高端应该是对设计对方法的研究与创新,甚至引发自己所处职业的一种潮流。
做好测试不是靠编程,而是靠的是严禁的作风,慎密的逻辑思维,适合的测试流程。从用户角度,到系统角度,到黑产角度,既保证给普通用户很好的用户体验,也保证系统运行平顺流畅,也保证不能应为hacker的攻击而功亏一篑
进入正题,最近在研究API接口中,异常测试用例的自动化问题,这边考虑的自动化,是通过接口说明文档,自动生成用例描述,用例的入参数据,用例的断言数据,当然测试的级别不是最高的,可以设置为2左右
比如一个注册接口,异常的测试用例,是不是需要判断,每一个必传入参是否传入,那这边就有2N条测试用例
1.请求传入的必传参数var1未传,验证返回var1....
2. 请求传入的必传参数var1传入的为空字符串(String类型)/null(..), 验证返回var1.....
异常测试用例还需要判断入参的长度,是不是又有了
3. 请求传入的参数var1超过最大长度限制,验证返回var1
有些入参有要求,比如用list,异常测试用例又有了
4.请求传入的参数Var1不是xx类型,验证返回
入参最好还需要判断是否将入参首位的空格去掉,异常测试用例又有了
5. 请求传入的入参首尾含有空格,验证存入DB中不含空格【要求代码对入参的首尾空格做trim()操作】
对接口的异常测试用例,弥漫着满满的套路气息,每次都进行编写测试用例,创建测试用例数据和断言等操作,入参多的时候,还是很费时间的,不利于提升工作效率。
更好的办法是:编写代码,自动生成测试用例描述,组装测试用例的数据,自动生成断言等
以前,我们一直用Jmeter创建的脚本来自动生成上述内容,
Jmeter生成jmx脚本,脚本中指定了入参个数、类型,长度等,之后生成用例描述,用例数据和断言
好处就是复用方便,更改下url直接测试
缺点就是,不利于动态生成用例,入参变化多了之后要重新创建新的脚本
还有一个缺点就是low,你若是说你用Jmeter做接口自动化测试的,大厂中厂都会嫌弃你low,因为人家是用Python做的,Java做的。
【low不low!!who cares?!!不是一样能完成任务吗,不一样能持续化集成并发送测试报告吗?你们一个组就100多号测试,也不就是完成这写接口的自动化测试吗,我们刚上手的实习生分分钟都能讲API测试用到飞】
感觉中国人,很喜欢用工具和方式来judge others,我们兄弟公司的人,大多是麻省理工学院的,api测试自动化还是用postman实现的呢,ui测试也只不过是protractor+jasmine等,人家不是low,够用就好,有时候已经不提倡测试,直接leader 做code review
现在动态实现接口异常测试用例的生成,用一个简单的例子
我们常见的接口说明文档,是不是长这样?
我页面还没开发完,大意就是讲入参,和比天性,类型,最大长度,等信息填入表中。
CREATE
TABLE
[DBO].[QA_APIVAR](
[APIVAR_ID] [
INT
] IDENTITY(1,1)
NOT
NULL
PRIMARY
KEY
,
[API_ID] [
INT
]
NOT
NULL
,
[APIVAR_NAME] [
VARCHAR
](100)
NULL
,
[APIVAR_INPUTFLAG] [
BIT
]
NOT
NULL
DEFAULT
1,
[APIVAR_INPUTDATATYPE] [
VARCHAR
](100)
NULL
,
[APIVAR_INPUTDATATYPEID]
INT
NOT
NULL
,
[APIVAR_INPUTLENGTH]
INT
NOT
NULL
,
[APIVAR_INPUTSCOPE] [
VARCHAR
](100)
NULL
,
[APIVAR_INPUTNOTE] [
VARCHAR
](200)
NULL
,
[APIVAR_DELETED_FLAG] [
BIT
]
NOT
NULL
DEFAULT
0,
[APIVAR_CREATEDT] DATETIME
NOT
NULL
,
[APIVAR_UPDATEDT] DATETIME
NOT
NULL
)
代码单元测试部分,判断必传入参的未传,生成测试用例描述,测试数据body【这边以json格式为sample】,断言暂未写
package
com.example.demo.api;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Controller;
import
org.springframework.web.bind.annotation.RequestMapping;
import
java.util.List;
import
java.util.Random;
@Controller
public
class
ApiVar2Case {
String ALLCHAR =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
;
@Autowired
private
ApiVarService apiVarService;
@Autowired
private
ApiCaseService apiCaseService;
@RequestMapping
(
"/CheckMustVar"
)
//根据必传参数,依次生成"请求传入的xx参数未传,验证返回"
public
void
CheckMustVar() {
List<ApiVarBean> list = apiVarService.CheckMustVar(
1
);
System.out.println(list);
System.out.println(list.size());
int
max =
0
;
String body =
null
;
for
(
int
i =
0
; i < list.size(); i++) {
String var = list.get(i).getVal();
var =
"请求中未传入"
+ var +
"验证返回"
+ var +
"~~更多断言"
;
System.out.println(var);
StringBuffer sb =
new
StringBuffer();
body =
"{ \n"
;
for
(
int
j =
0
; j < list.size(); j++) {
if
(list.get(i).getVal() != list.get(j).getVal()) {
Random random =
new
Random();
max = list.get(j).getInputLenght();
sb =
new
StringBuffer(
""
);
for
(
int
k =
0
; k < max; k++) {
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
}
body = body +
"\""
+ list.get(j).getVal() +
"\":\""
+ sb +
"\", \n"
;
}
}
body = body.substring(
0
, (body.length() -
3
)) +
" \n }"
;
System.out.println(body);
ApiCaseBean apiCaseBean =
new
ApiCaseBean();
apiCaseBean.setApiCase_taskid(
1
);
apiCaseBean.setApiCase_name(var);
apiCaseBean.setApiCase_body(body);
apiCaseBean.setApiCase_asseertion(
null
);
apiCaseBean.setApiCase_priorityid(
3
);
int
count = apiCaseService.save(apiCaseBean);
System.out.println(count);
}
}
//根据必传参数,依次生成"请求传入的XX参数为空字符串"
@RequestMapping
(
"/CheckMustVarEmpty"
)
public
void
CheckMustVarEmpty() {
List<ApiVarBean> list = apiVarService.CheckMustVar(
1
);
int
max =
0
;
String body =
null
;
for
(
int
i =
0
; i < list.size(); i++) {
String var = list.get(i).getVal();
var =
"请求中传入"
+ var +
"为空字符串验证返回"
+ var +
"~~更多断言"
;
System.out.println(var);
StringBuffer sb =
new
StringBuffer();
body =
"{ \n"
;
for
(
int
j =
0
; j < list.size(); j++) {
if
(list.get(i).getVal() != list.get(j).getVal()) {
Random random =
new
Random();
max = list.get(j).getInputLenght();
sb =
new
StringBuffer(
""
);
for
(
int
k =
0
; k < max; k++) {
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
}
body = body +
"\""
+ list.get(j).getVal() +
"\":\""
+ sb +
"\", \n"
;
}
else
{
body = body +
"\""
+ list.get(j).getVal() +
"\":\""
+
"\", \n"
;
}
}
body = body.substring(
0
, (body.length() -
3
)) +
" \n }"
;
ApiCaseBean apiCaseBean =
new
ApiCaseBean();
apiCaseBean.setApiCase_taskid(
1
);
apiCaseBean.setApiCase_name(var);
apiCaseBean.setApiCase_body(body);
apiCaseBean.setApiCase_asseertion(
null
);
apiCaseBean.setApiCase_priorityid(
3
);
int
count = apiCaseService.save(apiCaseBean);
System.out.println(count);
}
}
//根据接口中参数,依次生成"请求传入的XX参数为最大长度+1,即超过最大长度"
@RequestMapping
(
"/CheckVarOverLength"
)
public
void
CheckVarOverLength() {
List<ApiVarBean> list = apiVarService.CheckMustVar(
1
);
int
max =
0
;
String body =
null
;
for
(
int
i =
0
; i < list.size(); i++) {
String var = list.get(i).getVal();
int
length = list.get(i).getInputLenght();
var =
"请求中传入"
+ var +
"的长度为"
+ length +
"实际传入的长度为"
+ (length +
1
) +
"验证返回"
+ var +
"~~更多断言"
;
System.out.println(var);
StringBuffer sb =
new
StringBuffer();
body =
"{ \n"
;
for
(
int
j =
0
; j < list.size(); j++) {
Random random =
new
Random();
max = list.get(j).getInputLenght();
sb =
new
StringBuffer(
""
);
if
(list.get(i).getVal() != list.get(j).getVal()) {
for
(
int
k =
0
; k < max; k++) {
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
}
}
else
{
for
(
int
k =
0
; k <= max; k++) {
sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
}
}
body = body +
"\""
+ list.get(j).getVal() +
"\":\""
+ sb +
"\", \n"
;
}
body = body.substring(
0
, (body.length() -
3
)) +
" \n }"
;
ApiCaseBean apiCaseBean =
new
ApiCaseBean();
apiCaseBean.setApiCase_taskid(
1
);
apiCaseBean.setApiCase_name(var);
apiCaseBean.setApiCase_body(body);
apiCaseBean.setApiCase_asseertion(
null
);
apiCaseBean.setApiCase_priorityid(
3
);
int
count = apiCaseService.save(apiCaseBean);
System.out.println(count);
}
}
}
1 |
以下是生成的数据,我当然可以用个对象来接收,并存到数据库中去
[ApiCaseBean{num=1, val='name', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=5, InputNote='null'}, ApiCaseBean{num=2, val='ID', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=5, InputNote='null'}, ApiCaseBean{num=3, val='mobile', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=5, InputNote='null'}, ApiCaseBean{num=6, val='apple', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=6, InputNote='null'}, ApiCaseBean{num=7, val='orange', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=6, InputNote='null'}, ApiCaseBean{num=8, val='pear', InputFlag=1, InputDataType='String', InputTypeID=1, InputLenght=6, InputNote='null'}]
6
请求中未传入name验证返回name~~更多断言
{
"ID":"zHUX3",
"mobile":"0J9jR",
"apple":"BTOfiV",
"orange":"ZUz1DB",
"pear":"8vHDVB"}
请求中未传入ID验证返回ID~~更多断言
{
"name":"8gJfa",
"mobile":"5pKjY",
"apple":"7vZVSJ",
"orange":"45cTEN",
"pear":"v9FliS"}
请求中未传入mobile验证返回mobile~~更多断言
{
"name":"Bi5Xm",
"ID":"OmYSR",
"apple":"IEYHCO",
"orange":"1zPaB6",
"pear":"Jw0d84"}
请求中未传入apple验证返回apple~~更多断言
{
"name":"gesB1",
"ID":"fSCeE",
"mobile":"HmY6j",
"orange":"SKInay",
"pear":"kDeurf"}
请求中未传入orange验证返回orange~~更多断言
{
"name":"KnSwW",
"ID":"9VKd2",
"mobile":"thAXp",
"apple":"apjji8",
"pear":"J3UkLR"}
请求中未传入pear验证返回pear~~更多断言
{
"name":"OTKPo",
"ID":"5WgEh",
"mobile":"gfJZA",
"apple":"aXksSk",
"orange":"JCCGZp"}
生成测试用例的表
CREATE
TABLE
[DBO].[QA_APICASE](
[APICASE_ID] [
INT
] IDENTITY(1,1)
NOT
NULL
PRIMARY
KEY
,
[API_ID] [
INT
]
NOT
NULL
,
[APICASE_NAME] [
VARCHAR
](100)
NULL
,
[APICASE_BODY] [NVARCHAR](2000)
NULL
,
[APICASE_ASSERCTION] [
VARCHAR
](100)
NULL
,
[APICASE_PRIORITYID]
INT
,
[APICASE_PASSID]
INT
,
[APICASE_DELETED_FLAG] [
BIT
]
NOT
NULL
DEFAULT
0,
[APICASE_MEMO] [NVARCHAR](2000)
NULL
,
[APICASE_CREATEDT] DATETIME
NOT
NULL
,
[APICASE_UPDATEDT] DATETIME
NOT
NULL
)
有了用例描述和数据后,不管用什么接口测试工具,还是自已用Java/Python写的框架,导入数据即可
比如 https://www.cnblogs.com/qianjinyan/p/9951465.html
作者:夏天里的Jasmine
共同学习,写下你的评论
评论加载中...
作者其他优质文章