API 自动化框架

API 自动化框架

  个人认为接口自动化测试使用python语言编写更加简单,但所有接口自动化项目代码的思维都是一样的

1.项目包结构

1.case:存放用例数据的包,将所有用例数据以配置文件形式传入

2.core:核心包

  1)config.py:封装ConfigParser解析获取配置文件数据的方法

    python的内置模块ConfigParser:不太了解的可以百度

  2)log.py:封装log的模块

  3)request.py:封装接口测试的方法

  4)mysql.py:封装连接数据库的方法

3.function:功能包,封装执行用例的方法,以及生成测试报告的方法

  生成测试报告的原理:使用file生成.md文件,使用docker,pull mkdocs相关镜像,将data volum挂载到搭载测试报告的宿主机上,访问对应的域名即可

4.report:存放所有生成的测试报告

5.constant.py:存放所有全局变量的模块

6.run.py:运行测试用例,以及生成测试报告的模块

2.核心代码

 config.py

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 基础包:配置服务

import ConfigParser
import core.log as log

config = ConfigParser.ConfigParser()
logging = log.get_logger()

def get_config(filename):
    """
    获取文件配置
    :param filename: 配置文件名
    :return: None
    """
    global config
    try:
        config.read(filename)
        return True
    except Exception, e:
        logging.error("读取配置失败 %s" % e)

def get_data(title, key):
    """
    参数配置
    :param title: 配置文件的头信息
    :param key: 配置文件的key值
    :return: 配置文件的value
    """
    try:
        value = config.get(title, key)
        type(value)
        return value
    except Exception, e:
        logging.error("获取配置文件参数失败 %s" % e)

def get_title_list():
    """
    获取所有title
    :return: title list
    """
    try:
        title = config.sections()
        return str(title).decode("string_escape")
        # return ‘\n‘.join(title)
    except Exception, e:
        logging.error("获取title信息失败 %s", e)

  

mysql.py

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# author: zhizhi
# 基础包: MySQL

import pymysql.cursors
import core.log as log

logging = log.get_logger()
conn = None

def connect(host, user, password, db, charset=‘utf8‘):
    """
    链接Mysql
    :param host: 地址
    :param user: 用户
    :param password: 密码
    :param db: 数据库名
    :param charset: 数据类型
    :return: 链接
    """
    global conn
    if conn == None:
        conn = pymysql.connect(host=host,
                               user=user,
                               password=password,
                               db=db,
                               charset=charset,
                               cursorclass=pymysql.cursors.DictCursor)
    return conn

def execute(sql):
    """
    执行SQL
    :param sql: 执行的SQL
    :return: 影响行数
    """
    global conn
    try:
        with conn.cursor() as cursor:
            res = cursor.execute(sql)
        conn.commit()
        # 这里一定要写commit 不然提交的sql 都会被事务回滚
        return res
    except Exception, e:
        logging.error("sql is empty or error %s" % e)

def close():
    """
    关闭MySQL连接
    :return: None
    """
    global conn
    conn.close()

request.py

#!/usr/bin/python
#-*- coding: UTF-8 -*-
# 基础包:接口测试的封装

import requests
import core.log as log
import json

logging = log.get_logger()

def change_type(value):
    """
    对dict类型进行中文识别
    :param value: 传的数据值
    :return: 转码后的值
    """
    try:
        if isinstance(eval(value), str):
            return value
        if isinstance(eval(value), dict):
            result = eval(json.dumps(value))
            return result
    except Exception, e:
        logging.error("类型问题 %s", e)

def api(method, url, data ,headers):
    """
    自定义一个接口测试的方法
    :param method: 请求类型
    :param url: 地址
    :param data: 数据
    :param headers: 请求头
    :return: success(str)
    """
    global results
    try:
        if method == ("post" or "POST"):
            results = requests.post(url, data, headers=headers,cookies=cookie)
        if method == ("get" or "GET"):
            results = requests.get(url, data, headers=headers,cookies=cookie)

        response = results.json()
        success = response.get("success")
        return success
    except Exception, e:
        logging.error("service is error", e)

def set_cookieApi(method, url, data ,headers):
    """
    自定义一个登录接口测试的方法
    :param method: 请求类型
    :param url: 地址
    :param data: 数据
    :param headers: 请求头
    :return: success(bool)
    """
    global cookie
    try:
        if method == ("post" or "POST"):
            results = requests.post(url, data, headers=headers)
        if method == ("get" or "GET"):
            results = requests.get(url, data, headers=headers)
        response = results.json()
        success = str(response.get("success"))
        cookie = requests.utils.dict_from_cookiejar(results.cookies)
        return success
    except Exception, e:
        logging.info("LoginApi请求失败", e)

func.py: 可以通过接口返回数据与自己写的sql查询的数据进行对比,判断用例是否通过,所以提供了mysql通用模块

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 业务包:通用函数

import core.mysql as mysql
import core.log as log
import core.request as request
import core.config as conf
import constants as cs
import os

logging = log.get_logger()

class ApiTest:
    """接口测试业务类"""

    def __init__(self):
        pass

    def prepare_data(self, host, user, password, db, sql):
        """
        数据准备,添加测试数据
        :param host: 服务地址
        :param user: 用户
        :param password: 密码
        :param db: 数据库名
        :param sql: 执行的SQL
        :return:
        """
        mysql.connect(host, user, password, db)
        res = mysql.execute(sql)
        mysql.close()
        logging.info("Run sql: the row number affected is %s" % res)
        return res

    def get_prepare_sql(self, filename, key):
        """
        获取预备执行的SQL
        :param title: 配置文件头信息
        :param key: 配置文件值
        :return: Value
        """
        try:
            conf.get_config(filename)
            value = conf.get_data(title=cs.TITLE, key=key)
            return value
        except Exception, e:
            logging.error("获取用例参数值失败 %s" % e)

    def new_report_menu(self, filename):
        """
        这个方法主要是通过写入文件的方法,先打开cs.YML_REPORT也就是
        mkdocs.yml文件,判断文件中是否存在当前写入的内容。
        :param filename: 测试用例文件
        :return: 测试报告内容
        """
        try:
            result = os.path.exists(cs.REPORT_PATH)
            if result == True:
                conf.get_config(filename)
                reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT))
                report_name = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.R_NAME))
                file = open(cs.YML_REPORT, ‘r‘)
                list_con = file.readlines()
                content = str(list_con).decode("string_escape")
                fileContent = "- [%s, %s]"
                row = "\n"
                _content = fileContent % (reportName + cs.NOW, report_name)
                con = row + _content

                if _content not in content:
                    f = open(cs.YML_REPORT, ‘a+‘)
                    f.write(con)
                else:
                    logging.info("内容已经存在 %s" % _content)
        except Exception, e:
            logging.error("文件路径不存在 %s", e)

    def write_report(self, content):
        """
        这个方法用于书写测试报告从而解决之前的通过
        logging方式写入导致其他的日志无法实现写入
        :param content: 传入文件的内容
        :return: None
        """
        reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT))
        _reportName = reportName + cs.NOW
        filename = cs.REPORT_PATH + _reportName
        try:
            file = open(filename, ‘a+‘)
            file.writelines(content)
        except Exception, e:
            logging.error("文件路径不存在 %s", e)

    def execute_case(self, filename):
        """
        执行接口测试用例的方法
        :param filename: 用例文件名称
        :return: 测试结果
        """
        conf.get_config(filename)
        list = eval(conf.get_title_list())

        for i in range(1, len(list)):
            title = list[i]

            number = conf.get_data(title, key=cs.NUMBER)

            name = conf.get_data(title, key=cs.NAME)
            method = conf.get_data(title, key=cs.METHOD)
            url = conf.get_data(title, key=cs.URL)
            data = conf.get_data(title, key=cs.DATA)
            _data = request.json.dumps(data,ensure_ascii=False,indent=4)
            headers = eval(conf.get_data(title, key=cs.HEADERS))
            # headers[‘Cookie‘]=cookie
            _headers = request.json.dumps(headers,ensure_ascii=False,indent=4)

            testUrl = cs.DOMAIN + url
            login=cs.LOGIN
            if(title==login):
                actualCode = request.set_cookieApi(method, testUrl, data, headers)
            else:
                actualCode = str(request.api(method, testUrl, data, headers))

            expectCode = str(conf.get_data(title, key=cs.CODE))

            if actualCode != expectCode:
                logging.info("新增一条接口失败报告")
                self.write_report(cs.API_TEST_FAIL % (name, number, method, testUrl, headers,data, expectCode, actualCode))
            else:
                logging.info("新增一条接口成功报告")
                self.write_report(cs.API_TEST_SUCCESS % (name, number, method, testUrl, headers,data, expectCode, actualCode))

    def run_test(self, filename):
        """
        普通接口测试类方法
        :param filename: 接口的用例name
        :return: 测试报告
        """
        reportName =eval( conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT))

        _filename = cs.REPORT_PATH + reportName + cs.NOW
        try:
            if os.path.exists(_filename):
                os.remove(_filename)
                self.execute_case(filename)
            else:
                self.execute_case(filename)
        except Exception, e:
            logging.error("执行接口测试失败 %s", e)

    def write_report_result(self):
        """
        这个方法用于书写测试报告结果
        :return: None
        """
        reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT))
        _filename = cs.REPORT_PATH + reportName + cs.NOW
        try:
            f = file(_filename)
            content = f.read()
            if content != None:
                _count = content.count("Number")
                _fail = content.count("Case Fail")
                _pass = content.count("Case Pass")
                space = content.split(‘\n‘)
                space.insert(0,cs.RESULT_CONTENT % (_count, _pass, _fail))
                _content_ = ‘\n‘.join(space)
                fp = file(_filename,‘r+‘)
                fp.write(_content_)
        except Exception, e:
            logging.error("文件路径不存在 %s", e)

run.py

# !/usr/bin/python
# -*- coding: UTF-8 -*-
# 执行包:runscript

import function.func as func

ApiTest = func.ApiTest()

FILENAME = ‘login.ini‘

"""1.新建测试报告目录"""
ApiTest.new_report_menu(filename=func.cs.CASE_PATH+FILENAME)

"""2.执行测试用例"""
ApiTest.run_test(filename=func.cs.CASE_PATH+FILENAME)

"""3.统计测试报告结果"""
ApiTest.write_report_result()

配置文件:login.ini

[Test Report]
report = ‘Enterprise Version‘
reportName = ‘Regression Testing Report‘

[login]
number = 1
name = login
method = post
url = /s1/web/login
data = {data:{‘userCode‘:‘admin‘,‘password‘:‘[email protected]‘}}
headers = {‘Content-Type‘: ‘application/json;charset=UTF-8;‘}
code = True

[brand]
number = 2
name = get_brand
method = post
url = /s1/brand/getList
data = {"pageSize":10,"pageNum":1}
headers = {‘Content-Type‘: ‘application/json; charset=UTF-8;‘}
code = True

原文地址:https://www.cnblogs.com/shadow-yin/p/10678680.html

时间: 2024-09-28 19:47:02

API 自动化框架的相关文章

Python脚本之——API自动化框架总结

学完了Python脚本接口自动化之后,一直没有对该框架做总结,今天终于试着来做一份总结了. 框架结构如下图: 来说一下每个目录的作用: Configs:该目录下存放的是.conf,.ini文件格式的配置文件;文件里面的内容可以通过封装好的读写配置文件的类去获取. datas:该目录下存放一些测试用例数据,如:Excel libs:存放修改源码后的ddt.py和HTMLTestRunner文档,这个两个文档主要是为了让测试报告看起来更明了 logs: 存放脚本运行的日志文件 reports: 执行

CYQ.Data 从入门到放弃ORM系列:开篇:自动化框架编程思维

前言: 随着CYQ.Data 开始回归免费使用之后,发现用户的情绪越来越激动,为了保持这持续的激动性,让我有了开源的念头. 同时,由于框架经过这5-6年来的不断演进,以前发的早期教程已经太落后了,包括使用方式,及相关介绍,都容易引人误解. 为此,我打算重新写个系列来介绍最新的版本,让大伙从传统的ORM编程过渡到自动化框架型思维编程(自已造的词). 于是:这个新系列的名称就叫:CYQ.Data 从入门到放弃ORM系列 什么是:CYQ.Data 1:它是一个ORM框架. 2:它是一个数据层组件. 3

基于Selenium的web自动化框架

1 什么是selenium Selenium 是一个基于浏览器的自动化工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.Selenium WebDriver 和Selenium Grid: Selenium IDE:Firefox的一个扩展,它可以进行录制回放,并可以把录制的操作以多种语言(例如java,python等)的形式导出成测试用例. Selenium WebDriver:提供Web自动化所需的API,主要用作浏览

工作流和过程自动化框架 Camunda BPM

Camunda BPM 是一个灵活的工作流和过程自动化框架,它的核心是一个在Java虚拟机内部运行的原生BPMN 2.0流程引擎,因此它可以嵌入到任何Java应用程序或运行时容器中.Camunda BPM与Java EE 6集成,并可以与Spring Framework完美匹配. Camunda BPM平台还提供了一套丰富的.围绕BPM生命周期的组件: 流程实现和执行组件:camunda engine(负责执行BPMN 2.0流程).REST API.Spring/CDI集成 流程设计组件:ca

接口自动化框架好文

接口自动化框架好文 2017-04-13 API 自动化测试框架分享 接口测试的一些感悟 HTTP API自动化测试从手工到平台的演变

致网友Wonderfei的一封信(如何选择自动化框架的几点拙见)

注:本来这封信要发给Wonerfei网友的,但是因为每次只能发200字,所以干脆贴到博客上,叫Wonderfei同学到这上面来看,也算是我自己的一个临时总结吧.同时也希望大家给予Wonderfei相应的帮助,毕竟我自己的观点不一定正确和完整. Hi Wonderfei, 你好,由于我是博客新手,所以没有留意到你给我发的私信,不好意思. 首先由于我自己也是个新手,也是在学习各种框架然后给公司项目选定相应自动化框架,研究移动自动化测试框架也就近段时间而已,所以我只能从我自己今天为止的认知角度给各个框

【腾讯TMQ】5小时搞定谷歌原生自动化框架UiAutomator1.0

[腾讯TMQ]5小时搞定谷歌原生自动化框架UiAutomator1.0 前言 谷歌对UI测试(UI Tetsting)的概念是:确保用户在一系列操作过程中(例如键盘输入.点击菜单.弹出对话框.图像显示以及其他UI控件的改变),你的应用程序做出正确的UI响应. UI测试(功能测试.黑盒测试)的好处是不需要测试者了解应用程序的内部实现细节,只需要知道当执行了某些特定的动作后是否会得到其预期的输出.这种测试方法,在团队合作中可以更好地分离的开发和测试角色.然而常见的UI测试多是以手动方式去执行,然后去

Android自动化框架 模拟操作 模拟测试

转自:http://bbs2.c114.net/home.php?mod=space&uid=1025779&do=blog&id=5322 几种常见的Android自动化测试框架及其应用 随着Android应用得越来越广,越来越多的公司推出了自己移动应用测试平台.例如,百度的MTC.东软易测云.Testin云测试平台…….由于自己所在项目组就是做终端测试工具的,故抽空了解了下几种常见的基于UI层面的自动化测试工具.趁晚上有空总结下,好记心不如烂笔头呀! 一 常见Android自动

Android自动化框架

Android自动化框架 已有 2085 次阅读2014-8-26 12:19 | Android 几种常见的Android自动化测试框架及其应用 随着Android应用得越来越广,越来越多的公司推出了自己移动应用测试平台.例如,百度的MTC.东软易测云.Testin云测试平台…….由于自己所在项目组就是做终端测试工具的,故抽空了解了下几种常见的基于UI层面的自动化测试工具.趁晚上有空总结下,好记心不如烂笔头呀! 一 常见Android自动化测试框架及其应用 目前,Android基于UI层面的自