以conf命名的文件夹放配置文件。
已完成手机号的初始化操作:修改Excel。
常用方法:
1.利用Excel设置初始化手机号码,每次进行+1操作,以及变量替换。
2.每次从数据库里查询最大的手机号,在这个基础上加1。
3.每次清除完这个手机号码相关的数据,进行垃圾数据重置操作。
4.当前时间戳生成手机号码。
本篇文章先介绍一部分内容,未完待续。
logging是Python自带的一个日志模块。
它的主要作用有两个:
1.代替print,可以把大部分你想要进行调式的信息打印出来或者是输出到指定文件。
2.可以对一些输出的调试信息分类做输出,比如说:
DEBUG,INFO,WARNING,ERROR,CRITICAL
一般是看你对日志的级别定义是怎样就设置哪个级别的。
${变量名}
来自文件test_data_xiejinjieguo_shoujihao1.xlsx
来自文件case1.config
来自文件do_excel_shoujihao1.py
from openpyxl import load_workbook
from tools.read_config1 import ReadConfig
from tools import project_path1
import pandas as pd
#把Excel数据更新下,达到自动更新手机号,保持注册成功。
'''
已完成手机号的初始化操作:修改Excel
第一种操作:
利用Excel设置初始化手机号码,每次进行+1操作,以及变量替换。
参数替换成${变量名}
'''
class DoExcel:
@classmethod
def get_data(cls,file_name):
wb = load_workbook(file_name)
mode=eval(ReadConfig.get_config(project_path1.case_config_path, 'MODE', 'mode'))
tel=pd.read_excel(project_path1.test_case_path, sheet_name='init').ix[0, 0]#从Excel里面拿到的数据
test_data = []#把字典里所有数据都拿到
for key in mode:#遍历这个存在配置文件里的字典
sheet = wb[key]#key是表单名
if mode[key]=='all':
for i in range(2,sheet.max_row+1):#
row_data={}#字典
row_data['case_id']= sheet.cell(i, 1).value #行号 第1列第2行
row_data['url']=sheet.cell(i,2).value
# row_data['data'] = sheet.cell(i, 3).value
if sheet.cell(i,3).value.find('${tel_1}')!=-1:#有找到这个${tel_1}
row_data['data']=sheet.cell(i,3).value.replace('${tel_1}',str(tel))#替换的时候只能用字符串去替换
elif sheet.cell(i,3).value.find('${tel}')!=-1:
row_data['data'] = sheet.cell(i, 3).value.replace('${tel}', str(tel+1))
else:#如果没有找到的话
row_data['data'] = sheet.cell(i, 3).value
row_data['title'] = sheet.cell(i, 4).value
row_data['http_method'] = sheet.cell(i,5).value
row_data['expected'] = sheet.cell(i, 6).value#添加了一个期望值到测试数据里面去
row_data['sheet_name'] = key
test_data.append(row_data)
cls.update_tel(tel+2,file_name,'init')#更新手机号,针对Excel的操作。
#这里也是可以优化的?什么时候对手机号进行更新?更新的手机号是进行加1,还是加2?还是加3?
else:
for case_id in mode[key]:#
row_data = {} # 字典
row_data['case_id'] = sheet.cell(case_id+1, 1).value # 行号 第1列第2行
row_data['url'] = sheet.cell(case_id+1, 2).value
#做手机号的替换
if sheet.cell(i, 3).value.find('${tel_1}') != -1: # 有找到这个${tel_1}
row_data['data'] = sheet.cell(i, 3).value.replace('${tel_1}', str(tel)) # 替换的时候只能用字符串去替换
elif sheet.cell(i, 3).value.find('${tel}') != -1:
row_data['data'] = sheet.cell(i, 3).value.replace('${tel}', str(tel + 1))
else: # 如果没有找到的话
row_data['data'] = sheet.cell(i, 3).value
row_data['title'] = sheet.cell(case_id+1, 4).value
row_data['http_method'] = sheet.cell(case_id+1,5).value
row_data['expected'] = sheet.cell(case_id+1, 6).value # 添加了一个期望值到测试数据里面去
row_data['sheet_name']=key
test_data.append(row_data)
cls.update_tel(tel + 2, file_name, 'init') # 更新手机号,改造理由同上
return test_data
@staticmethod
#把结果写进Excel
def write_back(file_name,sheet_name,i,result,Testresult):#专门写回数据
wb=load_workbook(file_name)
sheet=wb[sheet_name]
sheet.cell(i,7).value=result
sheet.cell(i,8).value=Testresult
wb.save(file_name)#保存结果
@classmethod
def update_tel(cls,tel,filename,sheet_name):
#函数更新Excel里面手机号的数据
wb=load_workbook(filename)
sheet=wb[sheet_name]
sheet.cell(2,1).value=tel#赋值操作
wb.save(filename)
if __name__ =='__main__':
test_data=DoExcel().get_data(project_path1.test_case_path)
print(test_data)
来自文件get_data1.py
#反射:不管何时何地,只要传入一个类名,它就可以帮你操作。
from tools import project_path1
import pandas as pd
class GetData:
Cookie=None
#利用pandas从Excel里面拿到的手机号
来自文件http_request1.py
import requests
from tools.my_log1 import MyLog
my_logger=MyLog()
class HttpRequest:
@staticmethod
def http_request(url,data,http_method,cookie=None):
try :
if http_method.upper()=='POST':
res=requests.post(url,json=data,cookies=cookie)
# elif http_method.upper()=='POST':
# res=requests.post(url,data,cookies=cookie)
else:
my_logger.info("输入的请求方法不对")
except Exception as e:
my_logger.error("请求报错了:{0}".format(e))
raise e
return res#返回结果
if __name__ =='__main__':
#注册
register_url= 'http://api.nnzhp.cn/api/user/add_stu'
register_data= { "name":"niuhanyang","grade":"天蝎座","phone":'18614711314'}
#登录
login_url= 'http://api.nnzhp.cn/api/user/login'
login_data={"username": "niuhanyang", "passwd": 'aA123456'}
# 充值
recharge_url= 'http://api.nnzhp.cn/api/user/gold_add'
recharge_data={"stu_id": "2170", "gold": '1'}
login_res=HttpRequest().http_request(login_url,login_data,'post')
recharge_res=HttpRequest().http_request(recharge_url,recharge_data,'post',login_res.cookies)
print("充值结果:{}".format(recharge_res.json()))
来自文件my_log1.py
# 学习logging:引入日志模块
import logging#python自带的
class MyLog:
def my_log(self,msg,level):
#定义一个日志收集器 my_logger
my_logger=logging.getLogger('python2020')#调用getLogger定义一个日志收集器
#设定级别,setLevel
my_logger.setLevel('DEBUG')
#formatter设置日志最终输出格式
formatter=logging.Formatter('%(asctime)s-%(levelname)s-%(filename)s-%(name)s-日志信息:%(message)s')
#创建一个我们自己的输出渠道,StreamHandler是默认把它输出到控制台,但是它可以设置级别。
ch=logging.StreamHandler()
ch.setLevel('ERROR')
ch.setFormatter(formatter)
#输出到文本渠道,指定一个文件
fh=logging.FileHandler('py11.txt',encoding='UTF-8')
fh.setLevel('DEBUG')
fh.setFormatter(formatter)
#两者对接--指定输出渠道
my_logger.addHandler(ch)
my_logger.addHandler(fh)
#收集日志
if level=='DEBUG':
my_logger.debug(msg)
elif level=='INFO':
my_logger.info(msg)
elif level=='WARNING':
my_logger.warning(msg)
elif level=='ERROR':
my_logger.error(msg)
elif level=='CRITICAL':
my_logger.critical(msg)
#关闭渠道
my_logger.removeHandler(ch)
my_logger.removeHandler(fh)
def debug(self,msg):
self.my_log(msg,'DEBUG')
def info(self,msg):
self.my_log(msg,'INFO')
def error(self,msg):
self.my_log(msg,'ERROR')
if __name__ == '__main__':
pass
# my_logger=MyLog()
# my_logger.debug('可不可以这样?')
# my_logger.info('可行吗')
# MyLog().my_log('stone今天有点萌萌滴1','ERROR')
# MyLog().my_log('MIRACLE今天有点萌萌滴2', 'ERROR')
# MyLog().my_log('我是哆啦A梦鸭,今天有点萌萌滴3', 'ERROR')
来自文件project_path1.py
#路径的可配置
import os
'''专门来读取路径的值'''
project_path=os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]
#对路径进行了切割,返回了这样一个元组
# path=os.path.realpath(__file__)
#测试用例的路径
test_case_path=os.path.join(project_path,'test_data','test_data_xiejinjieguo_shoujihao1.xlsx')
#这就是绝对路径,顶级目录变,它就跟着变
#测试报告的路径
test_report_path=os.path.join(project_path,'test_result','html_report','test_api.html')
#配置文件的路径
case_config_path=os.path.join(project_path,'conf','case1.config')
# print(case_config_path)
#前提是test_data的上一级目录打开,并执行run文件。这种办法,文件在哪里执行都行。
#某个时间,相对路径很好用,但是如果参照物变了就不行了。绝对路径,换台电脑就不行了。
来自文件read_config1.py
import configparser
class ReadConfig:
@staticmethod
def get_config(file_path,section,option):
cf=configparser.ConfigParser()
cf.read(file_path)
return cf[section][option]
if __name__ == '__main__':
from tools import project_path1
print(ReadConfig.get_config(project_path1.case_config_path, 'MODE', 'mode'))
来自文件test_http_request_shoujihao1.py
import unittest
from tools.project_path1 import *
from tools.http_request1 import HttpRequest
from tools.get_data1 import GetData#反射
from ddt import ddt,data
from tools.do_excel_shoujihao1 import DoExcel
from tools.my_log1 import MyLog
test_data=DoExcel.get_data(test_case_path)#执行所有的用例
my_logger=MyLog()
@ddt#装饰测试类
class TestHttpRequest(unittest.TestCase):
def setUp(self):
pass
@data(*test_data)
def test_api(self,item):#ddt脱外套,以逗号去数有几个元素,每个元素都传进item这个参数
#数据类型必须是列表嵌套列表或者是列表嵌套字典,如果是列表嵌套列表,读数据的时候以索引的方式来读,
#如果是列表嵌套字典,读数据就以key的方式来读。
res=HttpRequest.http_request(item['url'],eval(item['data']),item['http_method'],getattr(GetData,'Cookie'))
if res.cookies:#利用反射存储cookie值
setattr(GetData,'Cookie',res.cookies)
try:
self.assertEqual(item['expected'],res.json()['error_code'])#做断言,是拿实际结果和期望结果去比对,判断用例通不通过,不加断言,根本没有期望结果,用例都是通过的。
#预期结果
TestResult='PASS'
except AssertionError as e:
TestResult='Failed'
my_logger.info('执行用例出错:{0}'.format(e))
raise e
finally:#加finally,不管用例有没有执行通过,它里面的代码是一定会执行的。
DoExcel.write_back(test_case_path,item['sheet_name'],item['case_id']+1,str(res.json()),TestResult)
my_logger.error('获取到的结果是:{0}'.format(res.json())) # 打印结果
def tearDown(self):
pass
来自文件run1
#方法二
#通过配置文件去决定执行哪个模块的用例。通过配置文件,以字典的形式key去存它的表单,
# value去存它执行所有用例还是些其它的用例
import unittest#引入单元测试
import HTMLTestRunner#HTML测试报告
from tools.project_path1 import *
from tools.test_http_request_shoujihao1 import TestHttpRequest
suite=unittest.TestSuite()
# suite.addTest(TestHttpRequest('test_api'))#测试类的实例
loader=unittest.TestLoader()
suite.addTest(loader.loadTestsFromTestCase(TestHttpRequest))
with open(test_report_path,'wb') as file:
#执行用例
runner=HTMLTestRunner.HTMLTestRunner(stream=file,
title='第一阶段项目实战',
description='这个是单元测试报告1115',
tester='清菡')
runner.run(suite)
我的文件结构如图:
运行以上文件的代码。输出结果如下:
每次运行之后,手机号都会更新成最新的,方便下次使用。
日志:记录应用的操作行为,操作记录。 五级最严重。
一级 DEBUG:最基础的级别。
二级 INFO:没有报错,只是想输出一条信息到日志里面去。
三级 WARNING:给出警告信息,如果出现这个错误,不至于出现宕机。
四级 EEROR:报错。
五级 CRITICAL:致命的。
常用的是EEROR,INFO。
日志默认是mode='a'的模式,只会追加,不会覆盖。
某一个请求要用到上一个请求的响应结果怎么办? 1.全局变量,2.反射,3.存在Excel里。
全局变量要是在另一个文件里,我要在当前文件引用怎么弄?
全局变量只能在当前文件里,不可以跨文件引用。这样的情况建议用反射。
只有测试用例可以test开头。
一般自动化开始之前,自己手工都已经测过了,产品比较稳定了。 主要自动化检测用户端,后台一般手动检测,时间多的话,可以用自动化。 管理后台主要测下类型,数据的异常这些情况。
补充《删库跑不动路》文章。
我删除mysql文件夹后清空了回收站,删除mysql文件夹的时候,我把mysql-essential-5.1.30-win32.msi安装文件也删除了,再次安装时重新从网盘下载的,Navicat Premium也卸载了,反正和mysql有关的一切都删除了。
全部卸载后,删除后重启了电脑。
为什么重启了电脑?
简单地说,大多数软件装完后,都需要修改注册表使其在电脑中占有“一席之地”,有些软件需要重启是因为它进入了注册表核心,但开机后的注册表核心已经像一面。
盾把该软件挡在了门外,该软件要进入,必须重启电脑,赶在那面盾建立起来之前融入注册表。
mysql数据库使用时候有个坑:
utf8是支持各国文字的,但对中文的支持确实不怎么地。插入数据前一定要设置。
set names gbk;
insert into people(id,name,sex,class_id,mobilephone) values(5622,'niuhanya','girl','1602','18210522044');