Unittest接口自动化测试

news2024/12/24 2:19:22

我又来了,来分享年前的unittest接口自动化实战啦。这次自动化接口框架比较简单,但是五脏俱全。(注:项目是针对我们公司内部系统的测试,我就不分享链接了。)

项目简介

项目名称:****名片系统

项目目的:实现系统项目自动化测试执行

项目版本:v1.0

项目目录

1

2

3

4

5

6

tools  #存放辅助方法   configEmail.py   #发送测试报告电子邮件

  HTMLTestRunner.py #第三方插件

  log.py #输出日志文件

  mail_receiver.txt #存放接收人邮箱地址

  read_json.py #读取单一测试数据json文件

  read_more_json #读取more测试数据json文件report #存放html测试报告logs  #存放输入日志文件data  #存放参数化测试数据(json文件)case  #存放测试用例api   #存放封装测试方法

 

 

 

caselist.txt    #存放要执行的测试用例

getpathInfo.py    #获取当前路径

runAll.py    #运行caselist.txt中的测试用例,输出测试报告 

项目框架

unittest单元测试框架

项目设计

1.每一个用例组合在一个测试类里面生成一个py文件

2.一个模块(被测项目功能)对应一个py文件及一个测试类(测试文件)

3.通过 parameterized 对参数进行参数化

项目目标

1. 生成测试用例执行结果报告

2.生成测试用例执行日志

3.用例执行失败或者执行完成后自动发送邮件报告

4.数据驱动(读取测试数据,减少脚本维护成本)

项目代码

  getpathInfo.py   #获取当前路径

import os

def get_Path():
    #获取上级路径
    #path = os.path.abspath(os.path.join(os.getcwd(), ".."))
    #获取当前路径
    path = os.path.split(os.path.realpath(__file__))[0]
    return path

if __name__ == '__main__':# 执行该文件,测试下是否OK
    print('测试路径是否OK,路径为:', get_Path())

  caselist.txt  #存放可执行测试用例  runAll.py   #运行文件


import os
import time

from BeautifulReport import BeautifulReport

import getpathInfo
import tools.HTMLTestRunner as HTMLTestRunner
import unittest
from tools.configEmail import send_email, getReceiverInfo
import tools.Log

path = getpathInfo.get_Path()
report_path = os.path.join(path, 'report')
log = tools.Log.logger

class AllTest:#定义一个类AllTest
    def __init__(self):#初始化一些参数和数据
        global resultPath
        resultPath = os.path.join(report_path)
        self.caseListFile = os.path.join(path, "caselist.txt")#配置执行哪些测试文件的配置文件路径
        self.caseFile = os.path.join(path, "case")#真正的测试断言文件路径
        self.caseList = []
        log.info('resultPath'+resultPath)#将resultPath的值输入到日志,方便定位查看问题
        log.info('caseListFile'+self.caseListFile)#同理
        log.info('caseList'+str(self.caseList))#同理

    def set_case_list(self):
        """
        读取caselist.txt文件中的用例名称,并添加到caselist元素组
        :return:
        """
        fb = open(self.caseListFile)
        for value in fb.readlines():
            data = str(value)
            if data != '' and not data.startswith("#"):# 如果data非空且不以#开头
                self.caseList.append(data.replace("\n", ""))#读取每行数据会将换行转换为\n,去掉每行数据中的\n
        fb.close()

    def set_case_suite(self):
        """
        :return:
        """
        self.set_case_list()#通过set_case_list()拿到caselist元素组
        test_suite = unittest.TestSuite()
        suite_module = []
        for case in self.caseList:#从caselist元素组中循环取出case
            case_name = case.split("/")[-1]#通过split函数来将aaa/bbb分割字符串,-1取后面,0取前面
            print(case_name+".py")#打印出取出来的名称
            #批量加载用例,第一个参数为用例存放路径,第一个参数为路径文件名
            discover = unittest.defaultTestLoader.discover(self.caseFile, pattern=case_name + '.py', top_level_dir=None)
            suite_module.append(discover)#将discover存入suite_module元素组
            print('suite_module:'+str(suite_module))
        if len(suite_module) > 0:#判断suite_module元素组是否存在元素
            for suite in suite_module:#如果存在,循环取出元素组内容,命名为suite
                for test_name in suite:#从discover中取出test_name,使用addTest添加到测试集
                    test_suite.addTest(test_name)
        else:
            print('else:')
            return None
        return test_suite#返回测试集

    def run(self):
        """
        run test
        :return:
        """
        try:
            suit = self.set_case_suite()#调用set_case_suite获取test_suite
            print('try')
            print(str(suit))
            if suit is not None:#判断test_suite是否为空
                print('if-suit')
                currTime = time.strftime('%Y-%m-%d %H_%M_%S')
                filename = currTime + '.html'
                # currTime = time.strftime('%Y-%m-%d %H_%M_%S')
                # fileName = report_path + r'\report'+ currTime + '.html'
                result = BeautifulReport(suit)
                result.report(filename= filename, description='接口测试报告')
                # fp = open(fileName, 'wb')
                # runner = HTMLTestRunner.HTMLTestReportCN \
                #     (stream=fp, title='自动化接口测试报告',
                #         description='处理器:Intel(R) Core(TM) '
                #                     'i5-5200U CPU @ 2.20GHz 2.20 GHz '
                #                     '内存:8G 系统类型: 64位 版本: windows 10 专业版')
                # runner.run(suit)
            else:
                print("Have no case to test.")
        except Exception as ex:
            print(str(ex))
            #log.info(str(ex))

        finally:
            print("*********TEST END*********")
            #log.info("*********TEST END*********")
            #fp.close()
        #发送测试邮件
        # read_msg = getReceiverInfo(
        #     r'F:\python_test\Automation_interfaceTest\tools\mail_receiver.txt')
        # sendmail = send_email(read_msg)
        # sendmail.sendEmail(fileName)
# pythoncom.CoInitialize()
# scheduler = BlockingScheduler()
# scheduler.add_job(AllTest().run, 'cron', day_of_week='1-5', hour=14, minute=59)
# scheduler.start()

if __name__ == '__main__':
    AllTest().run()

  tools   #辅助方法  configEmail.py  # 发送邮件


import os
import smtplib


import getpathInfo
from tools.Log import Logger
from email.mime.text import MIMEText
from email.header import Header
log = Logger(__name__)
path = getpathInfo.get_Path()
report_path = os.path.join(path, 'report')  # 存放测试报告文件的路径
mail_path = os.path.join(path,'tools')#存放收件人地址文件路径
class send_email():
    '''
        邮件配置信息
        '''

    def __init__(self,
                 receiver,
                 subject='*******',
                 server='smtp.qq.com',
                 fromuser='******',
                 frompassword='yjkxwfmrbumrbbce',
                 sender='*******'):
        """
        :param receiver:
        :param subject:
        :param server:
        :param fromuser:
        :param frompassword:
        :param sender:
        """

        self._server = server
        self._fromuser = fromuser
        self._frompassword = frompassword
        self._sender = sender
        self._receiver = receiver
        self._subject = subject

    def sendEmail(self, fileName):
        """
        :param filename:
        :return:
        """
        #   打开报告文件读取文件内容
        try:
            f = open(os.path.join(report_path, fileName), 'rb')
            fileMsg = f.read()
        except Exception:
            log.logger.exception(
                'open or read file [%s] failed,No such file or directory: %s' % (fileName, report_path))
            log.logger.info('open and read file [%s] successed!' % fileName)
        else:
            f.close()
            #   邮件主题
            subject = 'Python test report'  #
            #   邮件设置
            msg = MIMEText(fileMsg, 'html', 'utf-8')
            msg['subject'] = Header(subject, 'utf-8')
            msg['from'] = self._sender
            #   连接服务器,登录服务器,发送邮件
            try:
                smtp = smtplib.SMTP()
                smtp.connect(self._server)
                smtp.login(self._fromuser, self._frompassword)
            except Exception:
                log.logger.exception('connect [%s] server failed or username and password incorrect!' % smtp)
            else:
                log.logger.info('email server [%s] login success!' % smtp)
                try:
                    smtp.sendmail(self._sender, self._receiver, msg.as_string())
                except Exception:
                    log.logger.exception('send email failed!')
                else:
                    log.logger.info('send email successed!')


#   从文件中读取邮件接收人信息
def getReceiverInfo(fileName):
    '''
    :param filename: 读取接收邮件人信息
    :return: 接收邮件人信息
    '''
    try:
        openFile = open(os.path.join(mail_path, fileName))
    except Exception:
        log.logger.exception('open or read file [%s] failed,No such file or directory: %s' % (fileName, mail_path))
    else:
        log.logger.info('open file [%s] successed!' % fileName)
        for line in openFile:
            msg = [i.strip() for i in line.split(',')]
            log.logger.info('reading [%s] and got receiver value is [%s]' % (fileName, msg))
            return msg


if __name__ == '__main__':# 运营此文件来验证写的send_email是否正确
    readMsg = getReceiverInfo('mail_receiver.txt')
    sendmail = send_email(readMsg)
    sendmail.sendEmail('report.html')

1

HTMLTestRunner.py #第三方插件<br>log.py #输出日志文件

import os
import logging
import time
from logging.handlers import TimedRotatingFileHandler
import getpathInfo

path = getpathInfo.get_Path()
log_path = os.path.join(path, 'logs')  # 存放log文件的路径

class Logger(object):
    def __init__(self, logger_name='logs…'):
        self.logger = logging.getLogger(logger_name)
        logging.root.setLevel(logging.NOTSET)
        currTime = time.strftime("%Y-%m-%d")
        self.log_file_name = currTime+'logs'  # 日志文件的名称
        self.backup_count = 5  # 最多存放日志的数量
        # 日志输出级别
        self.console_output_level = 'WARNING'
        self.file_output_level = 'DEBUG'
        # 日志输出格式
        self.formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    def get_logger(self):
        """在logger中添加日志句柄并返回,如果logger已有句柄,则直接返回"""
        if not self.logger.handlers:  # 避免重复日志
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(self.formatter)
            console_handler.setLevel(self.console_output_level)
            self.logger.addHandler(console_handler)

            # 每天重新创建一个日志文件,最多保留backup_count份
            file_handler = TimedRotatingFileHandler(filename=os.path.join(log_path, self.log_file_name), when='D',
                                                    interval=1, backupCount=self.backup_count, delay=True,
                                                    encoding='utf-8')
            file_handler.setFormatter(self.formatter)
            file_handler.setLevel(self.file_output_level)
            self.logger.addHandler(file_handler)
        return self.logger


logger = Logger().get_logger()

 mail_receiver.txt  #存放接受人邮箱地址 read_json.py   # 读取单一测试数据 


import json
import getpathInfo

import os


class ReadJson(object):
    def __init__(self,filename):
        path = getpathInfo.get_Path()
        self.filepath = os.path.join(path, 'data')+"/"+filename

    def read_json(self):
         with open(self.filepath, "r", encoding="utf-8")as f:
            # 调用load方法加载文件流
            return json.load(f)

if __name__ == '__main__':
    data = ReadJson("updateuserpwd.json").read_json()
    arrs = []
    arrs.append((data.get("url"),
                data.get("userId"),
                data.get("data"),
                data.get("success"),
                data.get("message")))
    print(arrs)

 read_more_json.py   # 读取more测试数据 


import json


class ReadJson(object):
    def __init__(self,filename):
        self.filepath = '../data/' +filename

    def read_json(self):
         with open(self.filepath, "r", encoding="utf-8")as f:
            # 调用load方法加载文件流
            return json.load(f)

if __name__ == '__main__':
    datas = ReadJson("login_more.json").read_json()
    arrs = []
    for data in datas.values():
        arrs.append((data.get("url"),
                data.get("mobile"),
                data.get("code"),
                data.get("expect_result"),
                data.get("status_code")))
    print(arrs)

 #测试用例


import requests

class ApiLogin(object):

    def api_post_login(self,data):
        #headers定义
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        #url定义
        url = "http://*******"
        #调用post返回相应对象
        return requests.post(url, headers=headers,data = data)

#客户经理登录接口
import sys
import unittest
from api.api_login import ApiLogin
from parameterized import parameterized
from tools.read_more_json  import ReadJson
import tools.Log

log = tools.Log.logger

#读取数据函数
def get_data():
    datas = ReadJson('login.json').read_json()
    arrs = []
    for data in datas.values():
        arrs.append((data.get("data"),
                     data.get("message"),
                     data.get("desc")))
    return arrs

class TestLogin(unittest.TestCase):
    '''登录接口 '''
    @parameterized.expand(get_data())  # 参数化测试用例
    def test_login(self,data,message,desc):
        #调用登录方法
        s = ApiLogin().api_post_login(data)
        #调试使用添加描述
        self._testMethodDoc = desc
        #print('查看响应结果:',s.text)
        #断言响应信息
        self.assertIn(message,s.text)
        # 生成响应日志
        log.info('[%s]响应数据为:[%s]' % (sys._getframe().f_code.co_name, s.text))

if __name__ == '__main__':
    unittest.main()

#测试数据

{
   "login_001":{
               "data":{"loginName":"admin", "password": "123456","memberPass": "on"},
               "message": "名片管理系统",
               "desc": "正常登录"},
   "login_002": {
               "data":{"loginName":"admin", "password": "123456n","memberPass": "on"},
               "message": "密码不正确",
               "desc": "账号错误登录"},
   "login_003": {
               "data":{"loginName":"admir", "password": "123456","memberPass": "on"},
               "message": "账号不存在",
               "desc": "密码错误登录"},
   "login_004": {
               "data":{"loginName":" ", "password": "123456","memberPass": "on"},
               "message": "帐号密码登录",
               "desc": "密码为空登录"},
   "login_005": {
               "data":{"loginName":"admin", "password": " ","memberPass": "on"},
               "message": "密码不正确",
               "desc":"账号为空登录"},
   "login_006": {
               "data":{"loginName":"adm in", "password": "123456","memberPass": "on"},
               "message": "账号不存在",
               "desc":"账号存在空格登录"},
   "login_007": {
               "data":{"loginName":"admin", "password": "123 456","memberPass": "on"},
               "message": "密码不正确",
               "desc":"密码存在空格登录"},
   "login_008": {
               "data":{"loginName":"admin.", "password": "123456","memberPass": "on"},
               "message": "账号不存在",
               "desc":"账号存在特殊符号登录"},
   "login_009": {
               "data":{"loginName":"admin", "password": "123456.","memberPass": "on"},
               "message": "密码不正确",
               "desc":"密码存在特殊符号登录"},
   "login_010": {
               "data":{"loginName":"admi", "password": "123456","memberPass": "on"},
               "message": "账号不存在",
               "desc":"账号不完整登录"},
   "login_010": {
               "data":{"loginName":"admin", "password": "12345","memberPass": "on"},
               "message": "密码不正确",
               "desc":"密码不完整登录"}
}

 #测试报告

 就这样吧,其他测试用例与之类似就不展出了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1066768.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

wails window下打包安装包

官方文档https://wails.io/zh-Hans/docs/guides/windows-installer 版本&#xff1a;Wails CLI v2.6.0 问题 打包命令 wails build 打包出来的exe文件是直接打开的&#xff0c;不能包含程序安装功能 解决办法 1、chocolatey 安装包管理器工具安装 管理员身份打开powershell&a…

基于旗鱼优化的BP神经网络(分类应用) - 附代码

基于旗鱼优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于旗鱼优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.旗鱼优化BP神经网络3.1 BP神经网络参数设置3.2 旗鱼算法应用 4.测试结果&#xff1a;5.M…

vue解决:Parsing error: No Babel config file detected for ....

报错信息 Parsing error: No Babel config file detected for C:\Users\Admin\Desktop\shabi\work\src\App.vue. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. 分析错误&#xff1a;没有检测…

Pyside6 安装和简单界面开发

Pyside6 安装和简单界面开发 Pyside6介绍Pysied6开发环境搭建Python安装Pysied6安装 Pyside6界面开发简单界面设计界面设计界面编译 编写界面初始化代码软件打包 Pyside6介绍 对于Python的GUI开发来说&#xff0c;Python自带的可视化编程模块的功能较弱&#xff0c;PySide是跨…

嵌入式处理趋势,第一部分:超集成MCU

当今的嵌入式微控制器&#xff08;MCU&#xff09;是协同和创新的惊人例子。单个芯片上可容纳30,000至2百万个门&#xff0c;直到最近&#xff0c;各种集成的组件和模块都被视为独立的高级IC。 例如&#xff0c;当前典型的MCU设备&#xff08;下面的图1&#xff09;可能包含以…

【Kubernetes】深入了解 Kubernetes:现代容器编排与管理平台

前言 kubernetes&#xff0c;简称K8s&#xff0c;是用8代替名字中间的8个字符“ubernete”而成的缩写。是一个开源的&#xff0c;用于管理云平台中多个主机上的容器化的应用&#xff0c;Kubernetes的目标是让部署容器化的应用简单并且高效&#xff08;powerful&#xff09;,Kub…

【红日靶场】vulnstack3-完整渗透过程

系列文章目录 【红日靶场】vulnstack1-完整渗透过程 【红日靶场】vulnstack2-完整渗透过程 【红日靶场】vulnstack3-完整渗透过程 文章目录 系列文章目录基本信息环境配置开始渗透信息收集暴力破解漏洞利用绕过内网信息收集尝试上线msf上线msf横向移动msf 传达会话给cs横向到域…

关于IDEA中gradle项目bootrun无法进入断点以及gradle配置页面不全的解决方案

问题背景 在使用gradle编写的bootrun&#xff0c;采用debug方式启动项目时&#xff0c;无法进入断点&#xff0c;程序正常运行 并发现象1 此处无法识别为大象图标 点击右键后&#xff0c;没有圈中的这个选项 并发现象2 图片圈中的位置缺失 问题原因 正常的 run 命令是通过…

【状态估计】将Transformer和LSTM与EM算法结合到卡尔曼滤波器中,用于状态估计(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

蓝牙技术|Matter或能改变中国智能家居市场,蓝牙技术将得到进一步应用

近年来&#xff0c;智能家居开放协议标准Matter&#xff08;目前版本 1.1&#xff09;由连接标准联盟发布&#xff0c;该联盟是一个由数百家公司组成的全球性机构&#xff0c;旨在提供与物联网 (IoT) 相关的标准。例如&#xff0c;Matter 用于允许 Amazon Alexa、Apple Home、G…

【java源码】二甲医院his系统全套源码 云HIS系统源码

基层医院云HIS系统源码 一款满足基层医院各类业务需要的云HIS系统。该系统能帮助基层医院完成日常各类业务&#xff0c;提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等一系列常规功能&#xff0c;还能与公卫、PACS等各类外部系统融合&…

样式组件-样式失效问题

问题&#xff1a; 正常步骤&#xff08; npm install 安装样式组件引入到代码中使用less文件中&#xff0c;引入样式文件 import ‘~dtd/lib/style/themes/default.less’; &#xff09; 步骤之后&#xff0c;样式与网页展示不一致&#xff0c;样式没有正常显示 解决&#x…

第八课 二分

文章目录 第八课 二分lc704.二分查找--简单题目描述代码展示 二分模版lc34.排序数组中查找元素的第一个和最后一个位置--中等题目描述代码展示 lc69.x的平方根--简单题目描述代码展示 lc74.搜索二维矩阵--中等题目描述代码展示 lc153.寻找旋转排序数组中的最小值--中等题目描述…

剑指offer——JZ33 二叉搜索树的后序遍历序列 解题思路与具体代码【C++】

一、题目描述与要求 二叉搜索树的后序遍历序列_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入一个整数数组&#xff0c;判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回 true ,否则返回 false 。假设输入的数组的任意两个数字都互不相同。 数据范围&#xff…

12P2532X162-233A KJ3222X1-BA1 CE4003S2B3 EMERSON CONTROLLER

12P2532X162-233A KJ3222X1-BA1 CE4003S2B3 EMERSON CONTROLLER EDGEBoost I/O模块是一种可扩展的模块化解决方案&#xff0c;集成到Premio的工业计算机中&#xff0c;通过即插即用的可扩展性提供增强的可靠性。这些附加模块有助于解决在加固边缘出现的设计限制和兼容性问题。…

VUE3技术报告

文章目录 node和webstorm基本概念1. Node.js2. npm3.Webpack4. Vue webstorm创建vue项目1. 通过npx create-vue创建vue项目2. 通过npx --package vue/cli vue创建vue项目 VUE3起步-创建应用-挂载应用1. createApp 创建函数&mount挂载应用2. 创建应用中的data选项3. methods…

Django实战项目-学习任务系统-用户登录

第一步&#xff1a;先创建一个Django应用程序框架代码 1&#xff0c;先创建一个Django项目 django-admin startproject mysite将创建一个目录&#xff0c;其布局如下&#xff1a;mysite/manage.pymysite/__init__.pysettings.pyurls.pyasgi.pywsgi.py 2&#xff0c;再创建一个…

实时监视分析 IIS 日志

Microsoft IIS服务器&#xff0c;无论是Web还是FTP&#xff0c;对于企业来说都是必不可少的。但是&#xff0c;IT 安全管理员的工作并不止于部署 IIS 服务器&#xff0c;部署后&#xff0c;管理员必须采取安全措施来保护这些服务器&#xff0c;监视 IIS 服务器安全性的一种行之…

免杀对抗-反沙盒+反调试

反VT-沙盒检测-Go&Python 介绍&#xff1a; 近年来&#xff0c;各类恶意软件层出不穷&#xff0c;反病毒软件也更新了各种检测方案以提高检率。 其中比较有效的方案是动态沙箱检测技术&#xff0c;即通过在沙箱中运行程序并观察程序行为来判断程序是否为恶意程序。简单来说…

ubuntu 设置x11vnc服务

Ubuntu 18.04 设置x11vnc服务 自带的vino-server也可以用但是不好用&#xff0c;在ubuntu论坛上看见推荐的x11vnc&#xff08;ubuntu关于vnc的帮助页面&#xff09;&#xff0c;使用设置一下&#xff0c;结果发现有一些坑需要填&#xff0c;所以写下来方便下次使用 转载请说明…