CNAS能力验证-性能测试篇

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

本文章主要记录了CNAS性能测试能力认证中的前期准备方法、需求分析关注点、脚本编写抉择与场景设置得分点。


提示:以下是本篇文章正文内容,下面案例可供参考

一、前期准备概述

除了提前准备文档模板、编写套话之外,本次能力认证中,最重要的前期准备工作是根据以往出题需求编写模拟系统,并根据模拟系统和以往需求进行实操,在此步骤中我发现了大量性能测试中可能遇到的问题和模棱两可的选择,并提前得到解决,为正式测验打下基础。

二、模拟系统编写

1.编写公共方法

定义一个token如下(示例):

import time
import base64
import hmac


def generate_token(key, expire=1800):
    r'''
    @Args:
     key: str (用户给定的key,需要用户保存以便之后验证token,每次产生token时的key 都可以是同一个key)
     expire: int(最大有效时间,单位为s)
    @Return:
     state: str
    '''
    ts_str = str(time.time() + expire)
    ts_byte = ts_str.encode("utf-8")
    sha1_tshexstr = hmac.new(key.encode("utf-8"), ts_byte, 'sha1').hexdigest()
    token = ts_str + ':' + sha1_tshexstr
    b64_token = base64.urlsafe_b64encode(token.encode("utf-8"))
    return b64_token.decode("utf-8")

校验token是否正确:

import time
import base64
import hmac


def certify_token(token, key="UDq9aWLgxUHBdjXf"):
    r'''
    @Args:
     key: str
     token: str
    @Returns:
     boolean
    '''
    try:
        token_str = base64.urlsafe_b64decode(token).decode('utf-8')
        token_list = token_str.split(':')
        if len(token_list) != 2:
            return False
        ts_str = token_list[0]
        if float(ts_str) < time.time():
        # token expired
            return False
        known_sha1_tsstr = token_list[1]
        sha1 = hmac.new(key.encode("utf-8"), ts_str.encode('utf-8'), 'sha1')
        calc_sha1_tsstr = sha1.hexdigest()
        if calc_sha1_tsstr != known_sha1_tsstr:
            # token certification failed
            return False
            # token certification success
        return True
    except:
        return False

2.基于Python后端开发框架FastApi编写接口

根据需求编写模拟系统,系统需求:
1)验证各字段是否必填
2)根据token验证权限是否正确
3)正确存储库存数
4)response_body返回日志级msg,便于验证性能过程参数化是否如预期一致
5)根据请求成功与否返回不同的status_code,便于loadRunner分辨回放是否正确
6)日志记录所有请求,便于监督性能测试过程

定义接口长度和必填项公共校验方法(示例,非完整代码):

from fastapi import FastAPI, Body, Header, Response
from fastapi import APIRouter
import uvicorn
from typing import Optional
from pydantic import BaseModel, Field, validator


def sv(no):
    r = Field(..., max_length=no)
    return r

def nosv(no):
    r = Field(None, max_length=no)
    return r

def sf(no):
    r = Field(..., min_length=no, max_length=no)
    return r

编写被测接口(示例):

from tools.base import *
from starlette.responses import JSONResponse
from tools.assert_token import certify_token
from tools.set_token import generate_token
import os

app = APIRouter()


class login(BaseModel):
    user: str = sv(32)
    password: str = sv(32)


@app.post("/login", name="登录")
async def login(item: login):
    return JSONResponse(status_code=200, content={'code': 200, "message": "%s登录成功" % item.user,
                                                  "token": "%s" % generate_token("UDq9aWLgxUHBdjXf")})


class ruku(BaseModel):
    cfck: str = sv(32)
    splx: str = sv(32)
    sl: int = iv(10)


@app.post("/ruku", name="入库")
async def ruku(item: ruku,
                token: Optional[str] = Header()):
    file_name = os.path.join(os.path.dirname(__file__), "Data/Sales/num.txt")
    with open(file_name, "r+") as r:
        r1 = int(r.read()) + item.sl
        r.seek(0)
        r.write(str(r1))
    if certify_token(token) is not True:
        return JSONResponse(status_code=401,
                            content={'code': 401, "message": "token失效"})
    else:
        return JSONResponse(status_code=200,
                            content={'code': 200,
                                     "message": "{}入库{}数量{}成功,目前数量".format(item.cfck, item.splx, item.sl)})
                                     
class ruku_page(BaseModel):
    splx: str = nosv(32)
    rkdh: str = nosv(32)
    sl: int = noiv(10)
    rkrq: str = nosv(32)


@app.post("/ruku_page", name="入库记录查询")
async def ruku_page(item: ruku_page,
                token: Optional[str] = Header()):
    if certify_token(token) is not True:
        return JSONResponse(status_code=401,
                            content={'code': 401, "message": "token失效"})
    else:
        return JSONResponse(status_code=200, content={'code': 200,
                                                      "message": "{}{}{}{}入库查询成功".format(item.splx, item.rkdh,
                                                                                               item.sl, item.rkrq)})

编写服务启动main方法:

import xn_mock
from fastapi import FastAPI
import uvicorn

app = FastAPI()


app.include_router(xn_mock.app, prefix='/xn', tags=["性能测试系统"])

通过模拟系统总结出诸多测试点,在第三节详细描述。

三、正式脚本设计

1.录制前设置

设置基于URL的脚本
原因:基于HTML的脚本会导致login接口不能正确录制设置录制选项

设置UTF-8
原因:不勾选此项会导致脚本中文变为乱码

选择代理
原因:因为要使用Chrome录制,遂勾选此项
在这里插入图片描述

2.脚本修改

删除录制脚本中的css、js、图片请求
分析:css、js、图片等属于资源性请求,在一般系统开发中,图片由前端存储在专门的服务器或云端,与后端服务器关系不大,css、js等请求的压力主要在客户端,真实场景下会分布到每个用户电脑上,服务端压力不大。所以如果由测试负载机并发资源性请求,一是会导致测试负载机CPU和带宽压力过大,特别是带宽一定会占满;二是此请求对后端服务影响不大;故排除。

保留脚本中的html请求
分析:html是否保留,主要取决于是接口直接返回的完整html,还是通过nginx托管的静态网页。此处的html一是通过完整程度、动态程度判断大概是是接口直接返回的;二是登录接口重定向也是返回的html,无法排除;故所有html请求都保留。

保留脚本中的web_set_sockets_option(“SSL_VERSION”, “AUTO”)以及其他web_add_auto_header
分析:通过观察日志,即使加上web_set_sockets_option(“SSL_VERSION”, “AUTO”)方法,发出的请求依然是http而非https,应该是loadRunner内部有算法判断,所有删不删理论上应该没有影响,基于最大限度保留原始录制脚本的理念,此几项保留。

根据需求,使用lr_start_transaction和lr_end_transaction准确定义事务
分析:
1.录制之后脚本中会有多个接口,需要熟悉系统,准确定义事务的开始和结束,比如登录事务必须定位到login/form接口,而非login接口,入库查询事务必须定位到脚本中第二个queryList接口,不能是第一个queryList接口。
2.入库事务会例外地包含两个接口,因为点击入库同时触发了两个接口,从模拟用户操作的角度考虑,这两个接口可以视为一个动作,当然,从接口和线程的角度考虑也可以拆分开来,但是拆分后需要对第一个接口参数进行模拟,项目实战中可以实现,但在CANS考核中感觉有点超纲,讨论后决定从简使用一个事务包含两个接口的策略。
3.入库、出库完成后点击确定会自动触发一次刷新,需要将此刷新请求排除在事务之外。

在所有并发脚本的事务前设置lr_rendezvous(“集合点名称”)
分析:
1.遵从本次考核作业指导书,并发必须设置集合点
2.集合点必须设置在事务之前,因为线程集合也需要耗费时间
3.容量测试和在线测试脚本不能添加集合点

在所有事务前添加检查点web_reg_find
分析:
1.检查点尽量写在事务之外,因为检查点也会消耗极少的时间,事务内有多个请求的,检查点就只能写在事务内
2.对比每个需要检查的接口在正常、异常场景的返回,保证检查点检查的内容只有正常时才会返回,必要时对检查点进行参数化

对所有接口进行参数化
分析:
1.CNAS题目中对参数化的要求相当严格,每个用户能操作的仓库、物品都必须与需求一致,先通过EXCEL构建参数化模型,然后再从中复制数据到loadRunnerexcel参数化
2.我使用的方式是先定义用户参数,选择下一行=唯一,更新值时间=1次,即给每个用户绑定唯一的参数化值,且每次迭代都是同一个值。然后仓库和商品等参数选择下一行=same line as user,意思是当用户参数化取第N行时,仓库、商品等参数也取第N行,以此来保证并发下每次请求都符合用户、商品、仓库的对应关系
在这里插入图片描述

在这里插入图片描述

3.注意参数化的对象是所有接口而非所有事务,即事务外的过程接口也需要参数化,否则可能报错或者出现不符合需求的请求,比如过程中的查询接口也需要参数化用户,必须与登录用户一致
4.参数化有两个坑:一是参数类型要选择文件,不能选择表,选择表的话在调试的时候是正常的,但并发时会有报错;在这里插入图片描述

二是在编辑参数化是,需要在最后一行按回车,让光标保持在下一行入库如图位置,否则最后一行参数在并发时会读不到
在这里插入图片描述
5.入库数量不参数化,并发和在线测试固定为1,容量测试固定为50
6.在线场景时,注意要将参数化数据也按照3:4:3的比例进行分配,比如第一个脚本使用第1-30个用户及相关的仓库、物品,第二个脚本就应该使用第31-70个用户及相关的仓库、物品。

对有依赖关系的接口进行关联
分析:
1.入库脚本,在入库时需要传一个uuid,所以在获取uuid的接口前使用web_reg_save_param方法来抓取uuid,并将抓到的值定义为参数,再在入库接口传入{uuid},完成关联
2.出库脚本,同样也需要传uuid,但是出库获取的uuid格式是错误的,需要自己获取到之后进行拼接,组成正确的uuid,具体实现如图参数拼接
3.抓取参数的操作也尽量放在事务外,应该也会影响极少量的性能

构建性能测试数据
分析:
1.出库查询需要根据商品+最小出库数量~最大出库数量 组合条件进行查询,为保证每个用户都能查到数据,需要提前通过脚本为每个用户都构造一条出库数量为1的出库记录,且需要注意需求上有写:最大出库数量必须大于最小出库数量,所以只能传1到2
2.入库查询需要根据 商品+入库单号 组合条件进行查询,为保证每个用户都能查到数据,需要提前通过脚本为每个用户构建一条入库记录,并将入库单号参数化,注意在构建数据时,需要设置用户启用间隔时间,避免因为后启动的线程先完成请求,导致入库单号乱序
3.出库需要有库存才能出库,所以需要通过容量测试脚本先构建库存数据

3.脚本设置

勾选扩展日志-全选
原因:在并发完成后,通过抽查关键用户日志的方式,检查参数化是否如预期一致,比如抽查用户1(仓库一,物品一),用户11(仓库二,物品一),用户100(仓库十,物品十)

设置忽略思考时间
原因:是否忽略思考时间,请求数可能会有几十倍的差距,可以看做是性能测试的两种方案,一是通过添加思考时间极限模拟用户真实使用场景,二是忽略思考时间模拟该用户数量下可能存在的最大压力情况,由于添加思考时间会导致吞吐量验证减少,与“验证吞吐量是否满足10/sec”的需求相悖,且没有思考时间应该设置多长的依据,故经过思考和讨论,全部脚本都忽略思考时间。

关闭自动事务
原因:loadRunner默认勾选了将每个操作定义为一个事务,这样会导致结果报告展示混乱,且每秒事务通过总数表统计错误,故取消勾选

每次请求清除浏览器缓存
原因:需求中明确提出要清除浏览器缓存,故取消勾选 浏览器缓存-模拟浏览器缓存,勾选 每次迭代时模拟一个新用户,勾选每次迭代清除缓存。

设置迭代数
分析:
1.并发场景,迭代数为1
2.在线测试场景,迭代数为5-10
3.容量测试场景,迭代数满足需求容量即可,本次测验设置为201,因为需求要入100万条数据,即每个用户入1万条,每次最多入50个数据,所以迭代数=10000/50,大于200即可。

四、场景设计

初始化设置
分析:本次选择的是“在每个Vuser运行之前将其初始化”,有争议另一个选项是“同时初始化所有Vuser”,对性能测试结果几乎没有影响,前者是先执行用户1的init,然后执行用户1的action,再执行用户2的init,再执行用户2的action;后者是先执行用户1-100的init,再执行用户1-100的action。

启动Vuser设置
分析:本次选择的是同时启动所有用户,因为发现选择每秒启动用户时,集合点无法锁住用户,与集合点设置相悖,所以没有选择。

持续时间设置
分析:并发测试和在线测试,持续5分钟。容量测试选择完成前一直运行,意思就是指运行一次,运行一次足够构建需求的100万数据了。

停止Vuser设置
分析:本次选择同时停止全部Vuser,选线性停止应该也没什么影响。

百分比场景设置
分析:测试在线场景时,添加新场景-选择按百分比-选择三个目标脚本,然后依次分配30%,40%,30%在这里插入图片描述

五、测试结果关注点

并发测试关注点
分析:在CNAS的并发测试中,仅关注平均报告中的平均响应时间,前提是事务通过率大于95%,可以多次执行并发,找出最合适的结果进行记录在这里插入图片描述

在线测试关注点
分析:在CNAS的在线测试中,仅关注每秒事务总数,此图需要右键手动添加才能查看,前提依然是事务通过率大于95%,可以多次执行并发,找出最合适的结果进行记录
在这里插入图片描述
在这里插入图片描述

容量测试
分析:在CNAS的容量测试中,报告仅需关注事务摘要,即请求通过总数,另外需要被测软件自带的库存盘点功能辅助证明入库数达到需求容量。
在这里插入图片描述

总结

以上是本次CNAS性能测试所有关注点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值