zoukankan      html  css  js  c++  java
  • py自动化框架(二)

    import unittest
    import HTMLTestRunner
    from BeautifulReport import BeautifulReport
    class MyTest(unittest.TestCase):
    def setUp(self):
    #每条用例执行之前会执行setup
    print('这是setup')
    def tearDown(self):
    #每条用例执行之后都会执行teardown
    print('这是teardown')

    @classmethod
    def setUpClass(cls):
    #这个类里面的用例执行之前,最先执行它,最前面
    print('这是setupclass')

    @classmethod
    def tearDownClass(cls):
    #这个类里面所有的用例执行完之后执行它,最后面
    print('tearDownClass')


    def test_reg(self):
    '''注册'''
    print('reg')
    self.assertEqual(1,2,msg='token不对')
    def test_login(self):
    '''登录'''
    print('login')
    self.assertEqual(1,1)
    def test_buy(self):
    self.assertEqual(1,2,msg='购买失败')
    def test_z(self):
    self.assertIn(1,[1,23])
    def test_assert(self):
    res = False
    self.assertFalse(res,)
    print('test_assert')


    #下面这一坨是产生不好看的报告
    # f = open('report.html','wb')
    # runner = HTMLTestRunner.HTMLTestRunner(f,title='nhytest',
    # description='xxx接口测试')
    # sutie = unittest.makeSuite(MyTest)#变成测试集合
    # runner.run(sutie)


    suite = unittest.makeSuite(MyTest)#变成测试集合
    report = BeautifulReport(suite)
    report.report(filename='bfreport.html',description='接口测试报告')

    # 测试用例
    # 测试集合 testsuite 多个用例放在一起
    # testrunner 运行用例的
    # testloader 查找测试用例



    import unittest
    from parameterized import parameterized
    def login(username,password):
    print(username,password)
    print('=============')
    return 1

    class MyTest(unittest.TestCase):
    @parameterized.expand(
    [
    ['xiaodong','123','success'],
    ['yangfan','456','fail'],
    ['hailong','1273','success'],
    ['liurongxin','1273','success'],
    ]
    )
    def test_login(self,username,passwd,check):
    '正常登陆'
    res = login(username,passwd)
    self.assertEqual(check,res)

    unittest.main()

    自动化测试有两种驱动: 1、数据驱动 ,数据从excel/txt中来     

                                             2、代码驱动,有业务流程

    atp只能实现数据驱动

    utp能实现数据驱动和代码驱动

    注册---登录---抽奖  接口测试(代码驱动)

    test_cj.py

    import unittest
    from conf.setting import default_host
    from core.my_requests import MyRequest
    from core.tools import mysql,get_real_value
    from core.tools import r as redis

    class Cj(unittest.TestCase):

    password = 'aA123456'
    username = 'testhhh'

    def reg(self):
    '''注册接口'''
    url = '/api/user/user_reg'
    new_url = default_host + url
    data = {'username':self.username,'pwd':self.password,
    'cpwd':self.password}
    r = MyRequest(new_url,data)
    result = r.post()
    self.assertEqual(1,result.get('status'),msg='注册接口不通,%s'%result.get('data'))
    #校验接口是不是通的
    error_code = result.get('data').get('error_code')
    self.assertEqual(0,error_code,msg='注册失败,%s'%result.get('data'))
    sql ='select * from app_myuser where username = "%s";'%self.username
    sql_res = mysql.execute_one(sql)#执行sql
    self.assertIsNotNone(sql_res) #判断数据库返回的是否为空

    def login(self):
    '''登录接口'''
    url = default_host + '/api/user/login'
    data = {'username':self.username,'passwd':self.password}
    r = MyRequest(url,data)#发请求
    result = r.post()
    self.assertEqual(1,result.get('status'),msg='登录接口不通,%s'%result.get('data'))
    sign = get_real_value('sign',result)#从返回值里面取到sign的值
    self.assertIsNotNone(sign,msg='登录失败:%s'%result)#校验sign 校验的msg都是在失败的时候才会打印
    userid = get_real_value('userId',result)#从返回值里面取到userid的值
    return userid,sign

    def choujiang(self):
    '''抽奖接口'''
    url = default_host+'/api/product/choice'
    userid,sign = self.login()
    data = {'userid':userid,'sign':sign}
    r = MyRequest(url,data)
    result = r.get()
    self.assertEqual(1, result.get('status'), msg='抽奖接口不通,%s' % result.get('data'))
    redis_key ='choujiang:%s'%self.username
    count = redis.get(redis_key) #操作redis,取key
    self.assertEqual('1',count,'抽奖次数错误%s'%result) #redis中取出的count值是一个字符串
    sql='select count(*) as cishu from app_record where user_id = %s ;'%userid
    cishu = mysql.execute_one(sql).get('cishu') #执行sql execute_one(sql)返回的是一个字典,再从字典中取出cishu
    # {'cishu':1}
    self.assertEqual(1,cishu,'抽奖记录没有落到数据库里面!') #校验抽奖次数和数据库中是否对的上

    def test_choujiang(self):
    '''抽奖流程测试'''
    self.reg()
    self.choujiang()

    @classmethod
    def tearDownClass(cls):
    ##数据清除的工作 保证回归测试时 username能重复使用
    sql='delete from app_myuser where username="%s" ;'%cls.username
    mysql.execute_one(sql)
    key='choujiang:%s'%cls.username
    redis.delete(key)
    print('测试数据清理完成。。')


    # 有很多表要清除时
    #1、先把以前的数据库备份
    # mysqldump -uroot -p123456 -h192.168.1.13 db>/xxx/xx/a.sql
    # 2、执行自动化case
    # 3、把数据库恢复回来
    # sql.excute('RENAME database main TO main_20181204;')
    # sql.excute('create database main;')
    # os.system('mysql -uroot -p123456 -h192.168.1.13 db>/xxx/xx/a.sql')

    setting.py

    import os
    BAE_PATH = os.path.dirname(
    os.path.dirname(os.path.abspath(__file__))
    ) #atp的目录

    LOG_PATH = os.path.join(BAE_PATH,'logs') #log目录
    CASE_PATH = os.path.join(BAE_PATH,'cases') #case目录
    REPORT_PATH = os.path.join(BAE_PATH,'report') #report目录
    SQL_PATH = os.path.join(BAE_PATH,'sql_file') #存放sql的目录
    DATA_PATH = os.path.join(BAE_PATH,'data') #存参数化文件的地方


    MAIL_INFO = {
    'user':'xxx@qq.com',
    'password':'rtcxxxqrdgjcd',
    'host':'smtp.qq.com',
    'smtp_ssl':True,#发件箱是qq邮箱的话,改成True
    }

    TO = ['lihui@meizu.com']

    HOSTS = {
    'QA':'http://api.nnzhp.cn',#测试环境
    'DEV':'http://dev.nnzhp.cn',#开发环境
    'PRE':'http://pre.nnzhp.cn' #预生产环境
    }


    mysql_info = {
    'host':'118.24.3.40',
    'port':3306,
    'user':'besttest',
    'password':'HK139bc',
    'db':'main',
    'charset':'utf8',
    'autocommit':True
    }
    #mysql 配置信息
    redis_info = {
    'host': '118.24.3.40',
    'password': 'HK139bc&*',
    'port': 6379,
    'db': 0,
    'decode_responses': True
    }

    default_host = HOSTS.get('QA') #默认测试环境的地址

    my_requests.py

    import requests
    import nnlog
    import os
    from conf.setting import LOG_PATH
    class MyRequest:
    log_file_name = os.path.join(LOG_PATH,'MyRequest.log')#日子文件名
    time_out = 10 #请求超时时间
    def __init__(self,url,data=None,headers=None,file=None):
    self.url = url
    self.data = data
    self.headers = headers
    self.file = file
    def post(self):
    try:
    req = requests.post(self.url,data=self.data,headers=self.headers,
    files=self.file,timeout=self.time_out)
    except Exception as e:
    res = {"status":0,"data":e.args} #0代表请求失败
    else:
    try:
    res = {"status":1,"data":req.json()} #1代表返回的json
    except Exception as e:
    res = {"status":2,"data":req.text} #2代表返回不是json
    log_str = 'url: %s 请求方式:post data:%s ,返回数据:%s'%(self.url,self.data,res)
    self.write_log(log_str)
    return res

    def get(self):
    try:
    req = requests.get(self.url,params=self.data,headers=self.headers,timeout=self.time_out)
    except Exception as e:
    res = {"status":0,"data":e.args} #0代表请求失败
    else:
    try:
    res = {"status":1,"data":req.json()} #1代表返回的json

    except Exception as e:
    res = {"status":2,"data":req.text} #2代表返回不是json
    log_str = 'url: %s get请求 data:%s ,返回数据:%s'%(self.url,self.data,res)
    self.write_log(log_str)
    return res

    @classmethod
    def write_log(cls,content):
    log = nnlog.Logger(cls.log_file_name)
    log.debug(content)

    op_data.py

    import os
    from conf.setting import mysql_info,SQL_PATH
    from core.tools import mysql
    import datetime

    def get_mysql_info(): #从配置文件中取出数据库相关信息
    user = mysql_info.get('user')
    password = mysql_info.get('password')
    host = mysql_info.get('host')
    db = mysql_info.get('db')
    port = mysql_info.get('port')
    return user,password,host,db,port

    def bak_db(): #备份数据库
    user, password, host, db, port = get_mysql_info()
    sql_filename = datetime.datetime.now().strftime('%Y%m%d%H%M%S')+'.sql' #sql文件名称
    sql_filename = os.path.join(SQL_PATH,sql_filename)
    command = 'mysqldump -u{user} -p{pwd} -P{port} -h{host} {db} > {file}'.format(
    user=user,pwd=password,port=port,host=host,db=db,file=sql_filename
    )#执行备份数据库命令 mysqldump 最好写成绝对路径(找到mysqldump命令的位置)
    os.system(command) #os.system()执行操作系统命令
    print('数据备份完成!')
    return sql_filename #返回备份的数据库文件,恢复时还要用到

    def recover_db(sql_filename):
    user, password, host, db, port = get_mysql_info()
    new_db = db+'_'+datetime.datetime.now().strftime('%Y%m%d%H%M%S')
    sql='RENAME database %s TO %s; '%(db,new_db)#给原来的数据库改名
    mysql.execute_one(sql)
    print('数据库改名')
    sql2='create database %s charset utf8;'%db
    mysql.execute_one(sql2)
    print('新的数据库已经创建%s'%db)
    command = 'mysql -u{user} -p{pwd} -P{port} -h{host} {db} < {file}'.format(
    user=user, pwd=password, port=port, host=host, db=db, file=sql_filename
    ) #恢复数据库
    os.system(command)
    print('数据库恢复完成!')

    parse_param_file.py

    from conf.setting import DATA_PATH
    import os
    import xlrd

    def textFileToList(file,seq=','): #默认以逗号分隔
    file=os.path.join(DATA_PATH,file)
    print(file)
    case_data = []
    with open(file,encoding='utf-8') as f:
    for line in f:
    new_line = line.strip() #去掉空格 /n
    if new_line: #可能存在空行,去掉空行
    case_data.append(new_line.split(seq))
    return case_data

    def excelToList(file):
    file = os.path.join(DATA_PATH, file)
    workbook = xlrd.open_workbook(file)
    sheet = workbook.sheet_by_index(0)

    case_data = []
    for i in range(1,sheet.nrows):
    row_data = sheet.row_values(i)[4:8]
    case_data.append(row_data)

    return case_data

    tools.py

    import pymysql
    from conf.setting import mysql_info,redis_info
    import redis
    import jsonpath
    import datetime
    import os,yagmail
    from conf import setting

    class MySQL:
    def __init__(self):
    self.conn = pymysql.connect(**mysql_info)
    self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
    #初始化的时候就连接数据库
    def execute_many(self,sql):
    self.cur.execute(sql)
    res = self.cur.fetchall()
    if res:
    return res
    def execute_one(self,sql):
    self.cur.execute(sql)
    res = self.cur.fetchone()
    if res: #如果res不为NONE,再返回
    return res

    def __del__(self):
    self.cur.close()
    self.conn.close()
    print('连接已经关闭')

    def get_real_value(key,response):
    #从字典里面获取key对应的value
    res = jsonpath.jsonpath(response,'$..%s'%key)
    #$..%s这个是jsonpath这个模块的用法
    if res:
    return res[0]

    def get_redis():
    return redis.Redis(**redis_info)

    def make_today_dir():
    #创建当天的文件夹,返回绝对路径
    today = str(datetime.date.today())
    abs_path = os.path.join(setting.REPORT_PATH,today)
    #拼成当天的绝对路径
    if os.path.exists(abs_path):
    pass
    else:
    os.mkdir(abs_path)
    return abs_path

    def send_mail(content,file_path=None):
    #发邮件,传入邮件正文和附件
    m = yagmail.SMTP(**setting.MAIL_INFO,)
    subject = '接口测试报告_%s'%str(datetime.datetime.today())
    m.send(subject=subject,to=setting.TO,contents=content,attachments=file_path)


    mysql = MySQL()

    r = get_redis()

    start.py

    import unittest
    from BeautifulReport import BeautifulReport as bf
    from conf.setting import CASE_PATH
    from core.tools import make_today_dir,send_mail
    from core.op_data import bak_db,recover_db
    import os
    import datetime

    content = '''
    各位好!
    本次测试结果:总共运行%s条用例,通过%s条,失败%s条。详细信息见附件。
    '''

    def run_case():
    # sql_file = bak_db() #备份数据库函数
    suite = unittest.TestSuite() #建测试集合
    cases = unittest.defaultTestLoader.discover(CASE_PATH,'test*.py')
    #去某个目录下找测试用例
    for case in cases:
    suite.addTest(case) #循环把每个文件里面的case加入到测试集合里面
    report = bf(suite) #运行测试用例

    path = make_today_dir() #创建今天的文件夹,存放报告
    file_name = 'report_%s.html'%datetime.datetime.now().strftime('%H%M%S')#生成新的文件名
    report.report(filename=file_name,description='接口测试',log_path=path)#生成报告

    new_content = content%(report.success_count+report.failure_count,report.success_count,report.failure_count)
    abs_path = os.path.join(path,file_name)
    send_mail(new_content,abs_path)
    # recover_db(sql_file)#恢复数据库

    #产生报告
    run_case()




  • 相关阅读:
    Java封装
    SQLite学习手册(目录)
    如何在Mac系统安装eclipse并运行java程序?
    eclipse 常用快捷键
    mac的svn之cornerstone简易教程
    Mac环境下Myeclispe2015工具的安装与破解
    mysql 时间差问题集锦
    Eclipse怎么全局搜索替换(整个项目)
    Java关键字static
    几个linux 下C/C++集成开发环境推荐
  • 原文地址:https://www.cnblogs.com/mengmeng1011/p/12984371.html
Copyright © 2011-2022 走看看