Pytest测试实战
The pytest
framework makes it easy to write small, readable tests, and can scale to support complex functional testing for applications and libraries. 这段话很好地阐述了Pytest的设计思想与强大的特性。之前详细地阐述了Pytest测试框架搜索规则、Pytest测试框架执行方式、Pytest测试框架参数化、Pytest测试框架Fixture详解、Pytest测试框架中Conftest.py详解、Pytest测试框架常用命令与Pytest常用插件。Pytest测试框架另外一个优秀的特性是提供了支持分布式的执行,当需要被执行的测试用例很多的时候,使用分布式执行的方式提升自动化测试执行的效率,从而尽快的得到测试的结果。
pytest分布式执行
在自动化测试中,当被执行的测试用例个数在几百个甚至上千个测试用例的时候,那么这个时候执行的测试效率会非常低,一般执行的耗时都会在半小时或者是半小时以上,这么久的执行耗时一般不符合测试的诉求。特别是在集成回归测试与上线后的测试验证中,希望能够尽快地得到自动化测试用例执行的结果,从而得出测试的整体质量情况。因此提升自动化测试用例执行的效率是非常重要的。在Pytest测试框架中通过pytest-xdist插件的方式能够满足分布式执行被执行的测试用例,从而提升整体的测试效率。以下面的测试案例代码为案例,来详细的演示下分布式执行与未分布式执行的区别,案例代码如下:
#! /usr/bin/env python
# -*- coding:utf-8 -*-
# author:无涯
import os.path
import requests
import time
import pytest
def writeID(productID):
with open('productID','w') as f:
return f.write(str(productID))
def getProductID():
with open('productID') as f:
return f.read()
def addProduct(headers):
r=requests.post(
url='http://0.0.0.0:8000/interface/product/',
json={"name":"无涯课堂","product_type":"WEB","version":"V1.0.0","master":"无涯","description":"This Is A Test"},
headers=headers)
writeID(productID=r.json()['id'])
return r
def delProduct(headers):
r=requests.delete(
url='http://0.0.0.0:8000/interface/product/{productID}'.format(
productID=getProductID()),
headers=headers)
return r
def setProduct(headers):
r=requests.put(
url='http://0.0.0.0:8000/interface/product/{productID}/'.format(productID=getProductID()),
json={"name":"wuyaShare","product_type":"WEB","version":"V1.0.0","master":"无涯","description":"This Is A Test","id":getProductID()},
headers=headers)
return r
@pytest.fixture()
def apiInit(headers):
addProduct(headers=headers)
yield
delProduct(headers=headers)
def test_add_product(headers):
r=addProduct(headers=headers)
delProduct(headers=headers)
assert r.status_code==201
assert r.json()['name']=='无涯课堂'
def test_case_query(apiInit,headers):
r=requests.get(
url='http://0.0.0.0:8000/interface/products?name=无涯课堂',
headers=headers)
assert r.status_code==200
assert r.json()[0]['id']==int(getProductID())
def test_set_product_name(headers):
addProduct(headers=headers)
r=setProduct(headers=headers)
delProduct(headers=headers)
assert r.status_code==200
assert r.json()['name']=='wuyaShare'
def test_del_product(headers):
addProduct(headers=headers)
r=delProduct(headers=headers)
assert r.status_code==204
如上是一个产品模块中完整的测试用例,包含了增删改查的API测试用例,执行后的耗时以及结果信息如下:
从如上看,执行的耗时是1.73s,其实在实际的工作里面,编写的API自动化测试用例业务逻辑会非常复杂而且数量也会非常多,执行的耗时基本以分钟为单位。下面我们使用分布式执行的方式来执行同样的API测试用例,看执行的耗时。在分布式执行中,本质上是在执行的过程中开启多个work的进程,同时执行多个测试用例从而达到执行效率的提升,执行的命令如下:
pytest -v -s -n 1 test_platform.py
执行如上的结果后,执行的结果信息以及执行的耗时具体如下:
如上可以看到执行耗时并没有进行提升反而执行效率进行了下降,这是因为被执行的测试用例在基数上还是比较少,从开启work进程到同时执行多个测试用例的这个过程中也是需要耗时的,所以在使用分布式执行测试用例的过程中特别需要注意这点。在之前测试用例的基础上再增加测试用例的基数,常规执行的耗时以及结果信息如下:
再次使用分布式执行的方式来进行执行,本次执行开启2个work进程,执行的命令如下:
pytest -v -s -n auto test_platform.py
执行如上的命令后,执行的结果信息以及耗时结果如下:
如上结果中可以看到执行耗时在本次提升了约环比为19%的提升。在分布式执行的过程中,“-n”后面的数字代表的是CPU数目,一般而言使用“auto”它会自动检测到系统里的CPU数目。
分布式执行有它天然的优势但是也存在它的缺陷,特别是在参数化或者是多个work进程同时执行的时候操作同一个对象,中间会涉及到数据安全部分从而导致某些测试用例在分布式执行下失败,实际单独执行的时候是成功。后续文章详细地阐述下Python并发执行下数据安全的规则与过程。感谢您的阅读。