zoukankan      html  css  js  c++  java
  • unittest接口自动化测试

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

    项目简介

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

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

    项目版本:v1.0

    项目目录

    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())
    getpathInfo.py

      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("
    ", ""))#读取每行数据会将换行转换为
    ,去掉每行数据中的
    
            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'
    eport'+ 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_testAutomation_interfaceTest	oolsmail_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()
    runall.py

      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')
    configEmail.py
    HTMLTestRunner.py #第三方插件
    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()
    log.py

     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_json.py

     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)
    read_more_json.py

     #测试用例

    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)
    api_login.py
    #客户经理登录接口
    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()
    test_login.py

    #测试数据

    {
       "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":"密码不完整登录"}
    }
    test_login_data.json

     #测试报告

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

  • 相关阅读:
    事件冒泡
    jquery validation验证身份证号、护照、电话号码、email
    移动平台对 meta 标签的定义
    css3属性笔记
    渐变的参数
    各浏览器前缀
    Ubuntu20.04安装Matlab2018b
    win7 php安装使用
    mysql输入命令后没响应
    CentOS7上搭建Dokuwiki
  • 原文地址:https://www.cnblogs.com/MrqiuS/p/12900881.html
Copyright © 2011-2022 走看看