事件树算法(ETA)

Python RESTful API

事件树算法(ETA)、Python RESTful API

阅读文献

Event tree algorithms to generate test sequences for composite Web services

提出了一种替代中国邮递员问题(CPP)算法的事件树算法Event tree algorithm(ETA)。有两种策略可以用于减小测试套件的规模:

(1)cost-based greedy procedure用于构造事件树。

(2)定义一种方法来修剪树的冗余元素(剪枝

ETA (不选择策略), ETA+P (剪枝策略), GETA(贪婪算法), GETA+P (贪婪算法+剪枝策略)

四种算法介绍:

ETA.PNG

GREEDY:通过减少测试套件中事件的数量

替代基于广度优先搜索中的Lines12-25,每个节点依旧保持着它的高度,该算法有一个边集,其中的每个边都可以根据开销cost进行扩展。当树节点是一个叶子节点时,扩展边cost为1,(lines7-8,lines26-29)。当一个节点不是叶子节点,那么它所有的扩展边就会实现一个新的分支,开销cost更新则树节点+1,(lines16-20),这些规则可以计算边的开销,算法迭代直到所有的边被遍历(line9),总是首先扩展最低开销的边。

剪枝策略——优先考虑现有测试序列的扩展,以最低成本建立树的分支(例如最靠近根节点的)

greedy_tree.PNG

Pruning tree

剪枝条件:1.给定一个完全的事件树T=(V$T$,E$_T$,root),一个子树st=(V${st}$,E${st}$,root${st}$,)是T的子树如果root${st}$不是T的根节点并且root${st}$的父节点至少还有另一个孩子节点。2.如果移除子树st后T’依然可以覆盖所有的需求边。

Lines4-22区分可以剪枝的子树,Line9检查条件1,Line8检查条件2,定位后,变量canCutNode则指向子树的根节点,否则canCutNode为空。之后,算法剪枝子树Lines24-26,Line27更新边覆盖率。

prun_tree.PNG

四种算法对比:

GETA+P比CPP算法的产生时间平均减少了7%,产生的测试套件是CPP的2.24倍,

对比实验:CPP

衡量标准:Test suite size \ Number of test sequences \ Average test sequence length

实验结果:

generation time(faster->slowest):GETA+P -> GETA -> ETA+P -> ETA ->CPP

test suite size(smallest->largest):CPP-> GETA+P->GETA->ETA+P->ETA

nums of CES$_s$(lowest->highest):CPP->GETA+P->GETA->ETA+P->ETA

average test sequence length(shortest->longest):ETA->ETA+P->GETA->GETA+P->CPP

上述实验均是实验模型。

  • Selenium WebDriver – How To Test REST API**

UI测试存在的问题

  1. UI测试是非常慢的(这是因为—你的浏览器第一次发送请求给服务器以获取某些信息,一旦它获取了所需要的信息,可能需要一些时间来处理数据并通过下载以表格/适当的格式显示它们图像和应用样式等所以你必须等待所有这些过程完成才能与应用程序交互)
  2. 因为它很慢,所以它十分耗时
  3. 对于不同的浏览器测试,可能必须重复相同的测试集
  4. 浏览器是与selenium脚本分开的进程。 因此,同步始终是一个问题。
  5. UI测试有很多依赖项,如浏览器/版本/grid/驱动程序等

因此,这并不意味着我们应该始终进行API级别测试并发布产品。 我们应该尝试尽可能地进行API级别测试。 我们可以获得非常小的UI测试覆盖率.

REST API testing

与selenium web驱动程序UI测试相比,REST API测试并不是很困难。 大多数API应该是GET / POST / PUT / PATCH / DELETE请求之一。

  1. GET用于从后端获取信息以在UI中显示
  2. POST用于将新信息添加到后端
  3. PUT用于更新/替换任何现有信息
  4. PATCH用于部分更新
  5. DELETE用于从后端删除信息

Python RESTful API testing

构造REATful API

GET方法

1
2
3
4
5
6
7
8
9
10
11
# Get All Products
@app.route('/product',methods=['GET'])
def get_products():
all_products = Product.query.all()
result = products_schema.dump(all_products)
return jsonify(result.data)
# Get Single Product
@app.route('/product/<id>',methods=['GET'])
def get_product(id):
product = Product.query.get(id)
return product_schema.jsonify(product)

RESTful-get.PNG

RESTful-get1.PNG

POST方法

1
2
3
4
5
6
7
8
9
10
11
12
13
# Create a Product
@app.route('/product',methods=['POST'])
def add_product():
name = request.json['name']
description = request.json['description']
price = request.json['price']
qty = request.json['qty']

new_product = Product(name,description,price,qty)

db.session.add(new_product)
db.session.commit()
return product_schema.jsonify(new_product)

RESTful-post.PNG

PUT请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Update a Product
@app.route('/product/<id>',methods=['PUT'])
def update_product(id):
product = Product.query.get(id)
name = request.json['name']
description = request.json['description']
price = request.json['price']
qty = request.json['qty']

product.name = name
product.description = description
product.price = price
product.qty = qty
db.session.commit()
return product_schema.jsonify(product)

RESTful-put.PNG

DELETE请求

1
2
3
4
5
6
7
# Delete Product
@app.route('/product/<id>',methods=['DELETE'])
def delete_product(id):
product = Product.query.get(id)
db.session.delete(product)
db.session.commit()
return product_schema.jsonify(product)

RESTful-del.PNG