ApiAutoTest框架实现思路

框架的流程,个人是觉得有2个步骤比较有难度的,可以拿出来详细记录一下,毕竟就算自己做的东西,时间久了也是会忘记。

一、请求体数据量太大,应该怎么存放,如何实现代码、数据分离

问题:

   如果测试的接口是登录、注册类似的接口,请求体可能就是一行就够了,但是工厂后台的接口,大部分都是素材相关的接口,请求体内容很大,一般都有100-200行之间,下面是一个接口的请求体,展开看看130行左右。。

{
    "ImagePath": "/UpFile/C00003374/PMC/DesignMaterial/202009/9a76277bbe194ff8be5410b2c483331b/lALPBE1XYgg7RTDMyszK_202_202的副本3.png",
    "MaterialFileIds": [
        {
            "FilePath": "/UpFile/C00003374/PMC/DesignMaterial/202009/6dd6332d8f7d4d4ba7ae7348e3394017/lALPBE1XYgg7RTDMyszK_202_202的副本3.png",
            "FileBaseId": "1084968463",
            "Status": "0",
            "IsMainPic": false,
            "Files": []
        },
        {
            "FilePath": "/UpFile/C00003374/PMC/DesignMaterial/202009/6eead46ddee14da991cefa39d219b2cf/lALPBE1XYgg7RTDMyszK_202_202的副本8.png",
            "FileBaseId": "1084968602",
            "Status": "0",
            "IsMainPic": false,
            "Files": []
        },
        {
            "FilePath": "/UpFile/C00003374/PMC/DesignMaterial/202009/9a76277bbe194ff8be5410b2c483331b/lALPBE1XYgg7RTDMyszK_202_202的副本3.png",
            "FileBaseId": "1084978639",
            "Status": "0",
            "IsMainPic": true,
            "Files": []
        }
    ],
    "MaterialId": "113971677",
    "ProductId": "32553334",
    "MaterialName": "autotest",
    "PicWidth": "333",
    "PicHeight": "333",
    "Model": "333",
    "MaterialAttribute": "TilesCategory",
    "Property": "CeramicTile_Old",
    "description": "",
    "BindBrandSeries": {
        "BrandId": 100018819,
        "SeriesId": 100019718,
        "CategoryId": 6498114,
        "MaterialIds": [
            "113971677"
        ],
        "CombineState": 0
    },
    "RetailPrice": "333",
    "Is3d": 1,
    "IsPublic": 0,
    "materialBallType": 1,
    "Style": "15878",
    "Color": "19654",
    "Label": [
        {
            "CategoryId": "100019718",
            "CategoryName": "123456",
            "LableType": 4,
            "Status": "0"
        },
        {
            "CategoryId": "15878",
            "CategoryName": "现代",
            "LableType": 2,
            "Status": "0"
        },
        {
            "CategoryId": "19654",
            "CategoryName": "米色",
            "LableType": 1,
            "Status": "0"
        }
    ],
    "CategoryId": "9310643",
    "MixPaveSetting": "MPS_MultiBrickPave",
    "SpecialTexture": "SpecialTexture_Vertical",
    "FileList": [
        {
            "RecordID": "33192222",
            "AuxiliaryMaterialId": "113973591",
            "AuxiliaryMaterialName": "lALPBE1XYgg7RTDMyszK_202_202的副本3.png",
            "AuxiliaryImagePath": "/UpFile/C00003374/PMC/DesignMaterial/202009/6dd6332d8f7d4d4ba7ae7348e3394017/lALPBE1XYgg7RTDMyszK_202_202的副本3.png",
            "AuxiliaryImagePathId": "1084968463",
            "Status": "0"
        },
        {
            "RecordID": "33189918",
            "AuxiliaryMaterialId": "113971678",
            "AuxiliaryMaterialName": "lALPBE1XYgg7RTDMyszK_202_202的副本8.png",
            "AuxiliaryImagePath": "/UpFile/C00003374/PMC/DesignMaterial/202009/6eead46ddee14da991cefa39d219b2cf/lALPBE1XYgg7RTDMyszK_202_202的副本8.png",
            "AuxiliaryImagePathId": "1084968602",
            "Status": "0"
        }
    ],
    "MaterialExtensionID": "3736615",
    "IsHasProduct": 1,
    "BrickId": "31603",
    "IsBumpMap": 0,
    "Product": {
        "ProductName": "autotest",
        "Style": "15878",
        "CostPrice": "33",
        "RetailPrice": "333",
        "WholesalePrice": "333",
        "Color": "19654",
        "Unit": "bucket",
        "Detail": "%3Cp%3E8888%3Cimg%20src%3D%22/upfiles/image/20200924/6373657762525056354508274.png%22%20title%3D%22lALPBE1XYgg7RTDMyszK_202_202%u7684%u526F%u672C4.png%22%20alt%3D%22lALPBE1XYgg7RTDMyszK_202_202%u7684%u526F%u672C4.png%22/%3E%3C/p%3E",
        "IsYunhuojiaProduct": 0
    },
    "ProductIdToPrices": [
        {
            "RecordId": "1013976",
            "Code": "8",
            "ProductLevel": "8",
            "CostPrice": "8.00",
            "RetailPrice": "8.00",
            "Price": "8.00",
            "Status": "0"
        }
    ],
    "ProductImageFile": [
        {
            "FilePath": "/UpFile/C00003374/PMC/Product/202009/CC6397F6DA454017BCBB220BEAFDBF43/CC6397F6DA454017BCBB220BEAFDBF43_130x100.png",
            "FileId": "1084977107",
            "Status": "0"
        }
    ],
    "External": {
        "LinkUrl": "外链",
        "ExternalId": "2138211"
    },
    "bindTaoBaoProduct": {
        "item": "600231027677",
        "sku": "4220891757703",
        "wholesalePrice": "333",
        "untying": false,
        "status": 0
    }
}

需要实现大批量的接口自动化,这些接口的请求体数据应该怎么存放,而且,每个接口请求体的格式都不一样,那就做不了一份公共的数据公用所有接口,只能一个接口URL对应一个请求体。

前期,为了先实现功能,直接把请求体写死在代码里面,每次发版之前,在预发布环境跑一次,需要维护、变更的是时候,基本不想去动,因为真的毫无美感。。

解决方案:

有一段时间考虑过,想要直接从kibana里面取接口的请求体出来,因为应用的log都有写到es,但是,kibana数据量巨大,很难搜索到符合条件的测试数据,而且kiabna如果有问题,自动化测试就会全部报错,所以,这个方案也不是最好。

也测试过,网上很多同行的方法,把请求体放到Excel表格里面,如果是用户名、密码这些或者几行的请求体是可以的,但是把一个100多行的数据放到一个小格子里面,想一想也知道,看也不好看,改也难改,而且,本人也不喜欢Excel处理数据。

还有yaml的数据格式的,也尝试了,问题是,每次我想改数据,还需要研究一番,我的数据应该用什么样的格式改,但是,我的需求是,只想改完就走,越快越好,这明显不符合我的需求。而且,yaml的格式在python里面调用,还需要转为字典格式,更加增加了麻烦。

还有一种方案,数据存放在数据库,网上的方案都是用的mysql数据库,mysql数据库是关系型数据库,如果要把100多行的json字段写进去,就需要创建很多的字段,而且,不同的请求体数据,字段不一样,在一张表里面数据不统一,看起来就很乱,也不合适。

网上谷歌看了很多了也没有找到可以真正满意的方案,那一段时间忙于订单系统迁移、工厂后台版本测试工作量繁重,慢慢就放一边了。

直到一天,刷公众号,看到了一篇推文,提到MongoDB:

我的场景不也刚刚好符合吗,MongoDB是非关系型数据库,和mysql不一样,MongoDB的Bson和JSon格式的数据十分适合文档格式的存储与查询,而工厂后台接口的请求体的格式就是json的。

周末想起来这个事,就搞了起来,也是终于把MongoDB成功搭建到公司的机器上面了,经验教训:Linux系统装所有的服务,能用docker安装,绝对不装在宿主机,不然估计还肝几个通宵都不一定搞掂,环境出现的各种问题是不可预测的,

具体搭建过程记录如下:https://blog.csdn.net/zhoujunjunlove/article/details/108749683

实际效果如下:

把请求体的json数据和urlpath写到一个json里面,存放到MongoDB,测试用例调用pymongo库获取数据库的body数据,成功实现代码、数据分离。

import pymongo
from git_3weijia.ApiAutoTest.FmbApiAutoTest.conf.config import *
 
 
class FatchApiData():
    def __init__(self, host):
        # 从config文件读取数据库IP/port
        self.host = list(host.keys())[0]
        self.port = int(host[list(host.keys())[0]])
        # 创建一个pymongo对象
        self.connection = pymongo.MongoClient(self.host, self.port)
        # 连接mongo数据库fmb
        self.tdb = self.connection.fmb
        # 连接mongo数据库fmb的fmbapidata表
        self.collection = self.tdb.fmbapidata
 
    # 插入数据到mongo表
    def insert_mongo_one(self):
        dictdata = {"test": "demo"}
        self.collection.insert(dictdata)
        print(' insert dictdata done ')
        # 关闭数据库连接
        self.connection.close()
 
    # 查找数据库mongo表数据
    def select_mongo_one(self, url=None):
        result = self.collection.find_one({"urlpath": url})
        # print(result["body"])
        # 关闭数据库连接
        self.connection.close()
        return result
 
 
if __name__ == '__main__':
    a = FatchApiData(db_host)
    a.select_mongo_one("pmc/category/saveCategory")
    # a.insert_mongo_one()

二、如何组织接口测试用例,用何种设计模式,做到公共代码复用率高,减少重复代码,提高开发效率

工厂后台接口有几个特点:

1.请求体的格式不是统一的

2.响应结果的数据格式不是统一的

3.要符合业务场景,比如一个素材增删改查

这3个特点,就决定了,不能只用数据驱动来执行测试用例,就是,100个接口,只写一个test用例,用100份数据来驱动测试,这是行不通的,

因为100个接口的请求头accpt要求有json格式、form格式,响应结果格式也都不完全一样,而且要符合业务场景,就要下一个接口用例接收上一个用例返回来的值。

问题:

开发100个接口自动化测试用例,后续维护继续增加,慢慢可能就500、1000、2000,这些用例应该怎么存放?

解决方案:

1.按照系统的业务模块划分,一个模块对应一个文件夹;

2.按照系统的功能划分,一个功能对应文件夹里面的一个代码文件的测试类;

3.按照系统的模块-功能-接口细分,一个接口对应一个类里面的test方法

这样组织划分后,一个接口就对应测试报告的一行,如果报错了,可以快速找到报错的用例,后续系统业务变更,对应修改也方便。

问题:

这样就会出现另外一个问题,如果每个接口都需要写一个test方法,编写批量接口就会导致大量重复的代码,降低开发效率,所以,还需要考虑减少重复代码,提高开发效率。

解决方案:

正常来说,一般开发过程中就会考虑这个问题,我在写了10个接口的test方法后,就考虑应该怎么样把接口重复的代码去掉,有意思的是,在按照自己的想法去做优化后,回头看,其实就是面向对象开发的三大基本特征:封装、继承、多态。但是,在优化的时候是没有这个想法,说怎么做封装、继承、多态,而是在优化完了之后,才发现这些优化就是封装、继承、多态。而站在面向对象开发的三大基本特征的更高一个层次来看,应该就是工厂设计模型了。

工厂设计模型的原理可以看下:https://blog.csdn.net/zhoujunjunlove/article/details/109166882

简单说就是,把一个方法定义在基类里面,不去实现功能,在子类继承这个方法,再去实现功能。这种在父类里面定义接口(方法名就是接口的意思), 在子类实现这个方法,这种叫做工厂方法设计模型。

工厂模式在自动化测试中的应用

部分代码(比如获取MongoDB数据)是基本所有测试用例都需要写的,就定义一个基类publicObject,来实现这个方法,让子类apiObject、schemeObject、categoryObject继承这个方法;

而apiObject、schemeObject、categoryObject类代表不同模块的测试用例类的父类,在父类里面定义模块公用的方法,再让测试用例的类继承这些类;

这样,父类、父父类定义了方法,而功能是在测试类才实现,这样就可以把大量重复的代码放在父类、父父类,让测试类继承调用就可以。

比如:

父父类定义公共方法

父类继承父父类并定义新的方法

子类继承父类,并调用父父类的方法和父类的方法

这样一个test方法的接口用例,只需要几行代码就可以实现了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飘凛枫叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值