Python基础(9)——多线程、多进程、单元测试
目录
一、多线程、多进程
1、多线程与单线程
2、计算线程耗费时间
3、多线程处理一个数据
4、如何等待子线程完成后,通知数据导出完成
5、参数与返回值
6、锁
7、守护线程
8、队列
6、线程池
10、进程
二、单元测试
1、unittest
2、测试报告
正文:
一、多线程多进程
进程:
一个程序,它是一组资源的集合
一个进程里面默认是有一个线程的
线程:
最小的执行单位
线程和线程之间是互相独立的
主线程等待子线程执行结束
线程和线程之间数据是共享的
1、多线程与单线程
单线程时:
import threading import time def clean(): print('打扫卫生') time.sleep(2) def xiyifu(): print('洗衣服') time.sleep(3) def cook(): print('做饭') time.sleep(1) #单线程方式 clean() xiyifu() cook()

多线程时:
# 多线程 import threading import time
def clean(): print('打扫卫生') time.sleep(2) def xiyifu(): print('洗衣服') time.sleep(3) def cook(): print('做饭') time.sleep(1)
t = threading.Thread(target=clean) #子线程 t2=threading.Thread(target=xiyifu) t3=threading.Thread(target=cook) t.start() t2.start() t3.start() print(threading.activeCount())#当前的线程数 time.sleep(4) print(threading.activeCount())

2、 计算线程耗费时间:
单线程耗费时间:
# #单线程方式 主线程 start_time=time.time() clean() xiyifu() cook() end_time=time.time() print(end_time-start_time)

多线程耗费时间:
# 多线程 start_time=time.time() t = threading.Thread(target=clean) #子线程 t2=threading.Thread(target=xiyifu) t3=threading.Thread(target=cook) t.start() t2.start() t3.start() end_time=time.time() print(end_time-start_time)

0.003统计的是主线程执行的时间
线程和线程之间是互相独立的
# 多线程 start_time=time.time() t = threading.Thread(target=clean) #子线程 t2=threading.Thread(target=xiyifu) t3=threading.Thread(target=cook) t.start() t2.start() t3.start() # 主线程等待子线程(要子线程启动后,否则变为串行) t.join() t2.join() t3.join() end_time=time.time() print(end_time-start_time)

3、多线程处理一个数据
def export_data(): print(threading.current_thread()) #当前是哪个线程在运行 time.sleep(random.randint(1,5)) print('export_data') for i in range(10): t=threading.Thread(target=export_data) t=t.start()

4、如何等待子线程完成后,通知数据导出完成:
法1:把启动的子线程放到list中,在循环调用t.join
法2:判断当前的线程数
#方法1: thread_list=[] for i in range(10): t=threading.Thread(target=export_data) thread_list.append(t) t = t.start() # if threading.current_thread()==1: # t.join() for t in thread_list: t.join() print('数据都导完了')
。。。

#方法2:等待多个子线程执行结束,判断当前线程数 for i in range(10): t=threading.Thread(target=export_data) t = t.start() while threading.active_count()!=1: pass print('数据都导完了')

5、多线程的参数与返回值
result_list=[] #存储返回值 def export_data2(db,excel): print(threading.current_thread()) print('export_data',db,excel) time.sleep(random.randint(1,5)) result_list.append(random.randint(1,5)) for i in range(10): t=threading.Thread(target=export_data2,args=['db1','a.xls']) t = t.start() while threading.active_count()!=1: pass
print ('数据都导完了')
。。。

练习:
使用多线程方式下载图片
import threading import requests import auto_install #自己写的小工具,md5加密使用 def down_load_pic(url): print('开始下载',url) r=requests.get(url) file_name=auto_install.InstallRequrie.md5(url)+'.jpg' with open(file_name,'wb') as fw: fw.write(r.content) urls = [ 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3353166494,2700282750&fm=26&gp=0.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603003159808&di=7a97fdd275ec4e0fc4ab54bdb8a2e703&imgtype=0&src=http%3A%2F%2Fwww.pc6.com%2Fup%2F2011-12%2F201112918444441530.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603003159808&di=0ae20fe3bd8759c059cb4432938e4062&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20181209%2F38467a58f9264ca68eefa37719b4b739.jpeg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603003159807&di=5040439b916279a7106a7660b7e0168a&imgtype=0&src=http%3A%2F%2Fimg1.cache.netease.com%2Fcatchpic%2FE%2FE5%2FE5DD0A8099E2D28226465C6894F7A7A1.jpg' ] for url in urls: t=threading.Thread(target=down_load_pic,args=[url]) t.start() while threading.active_count()!=1: pass print('所有图片下载完成')

以上会启动线程过多导致死机,应使用:
import threading import requests import auto_install def down_load_pic(url): print('开始下载',url) r = requests.get(url) file_name = auto_install.InstallRequire.md5(url) + '.jpg' with open(file_name,'wb') as fw: fw.write(r.content) def down_load_pics(urls): print('开始下载',urls) for url in urls: r = requests.get(url) file_name = auto_install.InstallRequire.md5(url) + '.jpg' with open(file_name,'wb') as fw: fw.write(r.content) urls = [ 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3353166494,2700282750&fm=26&gp=0.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603003159808&di=7a97fdd275ec4e0fc4ab54bdb8a2e703&imgtype=0&src=http%3A%2F%2Fwww.pc6.com%2Fup%2F2011-12%2F201112918444441530.jpg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603003159808&di=0ae20fe3bd8759c059cb4432938e4062&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20181209%2F38467a58f9264ca68eefa37719b4b739.jpeg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603003159807&di=5040439b916279a7106a7660b7e0168a&imgtype=0&src=http%3A%2F%2Fimg1.cache.netease.com%2Fcatchpic%2FE%2FE5%2FE5DD0A8099E2D28226465C6894F7A7A1.jpg' ] for i in range(10): step = len(urls) / 10 t = threading.Thread(target=down_load_pics,args=[step]) while threading.active_count()!=1: pass #50线程,平均分配给每个线程 print('所有图片下载完成')
6、锁
线程和线程之间数据是共享的
import threading count = 0 lock=threading.Lock() def add(): global count for i in range(100000): lock.acquire() #加锁 count+=1 lock.release() #解锁 #方法2: #for i in range(100000): # with lock: # count+=1 for i in range(2): t=threading.Thread(target=add) t.start() while threading.active_count()!=1: pass print(count)
7、守护线程
不管子线程是否结束,主线程结束其他均结束
未设置守护线程
import threading import time import random def talk(name): print('正在和%s聊天'%name) time.sleep(random.randint(1,5)) print('和%s聊完了'%name) t = threading.Thread(target=talk,args=['yinluming']) # t.setDaemon(True)#设置为守护线程 t.start() t = threading.Thread(target=talk,args=['yinluming1']) # t.setDaemon(True)#设置为守护线程 t.start() t = threading.Thread(target=talk,args=['yinluming2']) # t.setDaemon(True)#设置为守护线程 t.start() t = threading.Thread(target=talk,args=['yinluming3']) # t.setDaemon(True)#设置为守护线程 t.start() print('退出qq')

设置守护线程
import threading import time import random def talk(name): print('正在和%s聊天'%name) time.sleep(random.randint(1,5)) print('和%s聊完了'%name) t = threading.Thread(target=talk,args=['yinluming']) t.setDaemon(True)#设置为守护线程 t.start() t = threading.Thread(target=talk,args=['yinluming1']) t.setDaemon(True)#设置为守护线程 t.start() t = threading.Thread(target=talk,args=['yinluming2']) t.setDaemon(True)#设置为守护线程 t.start() t = threading.Thread(target=talk,args=['yinluming3']) t.setDaemon(True)#设置为守护线程 t.start() # with threading.active_count()!=1: # pass print('退出qq')

8、队列
#队列 import queue import random import time import threading order_q = queue.Queue() #生产者/消费者模式 def producer(): for i in range(100): order_id=random.randint(1,99999) print('订单生成,order_id:%s'%order_id) order_q.put(order_id) #放入队列 time.sleep(1) def consumer(): while True: if order_q.qsize()>1: order_id=order_q.get() #消费 print('订单落库:',order_id) t=threading.Thread(target=producer) t.start() t=threading.Thread(target=consumer) t.start()

多个消费者时:
def consumer(): while True: if order_q.qsize()>1: order_id=order_q.get() print('consumer1订单落库:',order_id) def consumer2(): while True: if order_q.qsize()>1: order_id=order_q.get() print('consumer2订单落库:',order_id) t=threading.Thread(target=producer) t.start() t=threading.Thread(target=consumer) t.start() t=threading.Thread(target=consumer2) t.start()

队列的作用:
1)异步处理
2)保证顺序
9、线程池
安装线程池模块:pip install threadpool
import threadpool import requests import auto_install import threading def down_load_pics(url): print(threading.current_thread()) print('开始下载',url) r=requests.get(url) file_name=auto_install.InstallRequrie.md5(url)+'.jpg' with open(file_name,'wb') as fw: fw.write(r.content) urls = ['https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140','https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140','https://q4.qlogo.cn/g?b=qq&nk=1473732204&s=140','https://q4.qlogo.cn/g?b=qq&nk=974757912&s=140','https://q4.qlogo.cn/g? b=qq&nk=1649366257&s=140','https://q4.qlogo.cn/g?b=qq&nk=1031884559&s=140','https://q4.qlogo.cn/g?b=qq&nk=875197774&s=140','https://q4.qlogo.cn/g?b=qq&nk=821254160&s=140','https://q4.qlogo.cn/g?b=qq&nk=573865240&s=140','https://q4.qlogo.cn/g?b=qq&nk=1390187782&s=140','https://q4.qlogo.cn/g?b=qq&nk=794731904&s=140','https://q4.qlogo.cn/g?b=qq&nk=752453244&s=140','https://q4.qlogo.cn/g?b=qq&nk=21007874&s=140','https://q4.qlogo.cn/g? b=qq&nk=799547450&s=140','https://q4.qlogo.cn/g?b=qq&nk=1072107057&s=140','https://q4.qlogo.cn/g?b=qq&nk=1916515489&s=140','https://q4.qlogo.cn/g?b=qq&nk=2472761190&s=140','https://q4.qlogo.cn/g?b=qq&nk=516481730&s=140','https://q4.qlogo.cn/g?b=qq&nk=769855584&s=140','https://q4.qlogo.cn/g?b=qq&nk=1219841454&s=140','https://q4.qlogo.cn/g?b=qq&nk=806930450&s=140','https://q4.qlogo.cn/g?b=qq&nk=865020636&s=140','https://q4.qlogo.cn/g? b=qq&nk=294142908&s=140','https://q4.qlogo.cn/g?b=qq&nk=602647962&s=140','https://q4.qlogo.cn/g?b=qq&nk=429255693&s=140','https://q4.qlogo.cn/g?b=qq&nk=455525857&s=140','https://q4.qlogo.cn/g?b=qq&nk=173547362&s=140','https:// q4.qlogo.cn/g?b=qq&nk=739124752&s=140','https://q4.qlogo.cn/g?b=qq&nk=947078208&s=140','https://q4.qlogo.cn/g?b=qq&nk=846913816&s=140','https://q4.qlogo.cn/g?b=qq&nk=1561131041&s=140','https://q4.qlogo.cn/g? b=qq&nk=1113092340&s=140','https://q4.qlogo.cn/g?b=qq&nk=1123414020&s=140','https://q4.qlogo.cn/g?b=qq&nk=584277761&s=140','https://q4.qlogo.cn/g?b=qq&nk=694900554&s=140','https://q4.qlogo.cn/g?b=qq&nk=2264715013&s=140','https://q4.qlogo.cn/g?b=qq&nk=1345741814&s=140','https://q4.qlogo.cn/g?b=qq&nk=623342455&s=140','https://q4.qlogo.cn/g?b=qq&nk=1021283465&s=140','https://q4.qlogo.cn/g?b=qq&nk=675600120&s=140','https://q4.qlogo.cn/g? b=qq&nk=2503297190&s=140','https://q4.qlogo.cn/g?b=qq&nk=1765242270&s=140','https://q4.qlogo.cn/g?b=qq&nk=2273747892&s=140','https://q4.qlogo.cn/g?b=qq&nk=526962645&s=140','https://q4.qlogo.cn/g?b=qq&nk=1522503760&s=140','https://q4.qlogo.cn/g?b=qq&nk=690942492&s=140','https://q4.qlogo.cn/g?b=qq&nk=705768596&s=140','https://q4.qlogo.cn/g?b=qq&nk=2496140985&s=140','https://q4.qlogo.cn/g?b=qq&nk=690763103&s=140','https://q4.qlogo.cn/g? b=qq&nk=935306254&s=140','https://q4.qlogo.cn/g?b=qq&nk=649055943&s=140','https://q4.qlogo.cn/g?b=qq&nk=373235798&s=140','https://q4.qlogo.cn/g?b=qq&nk=386756529&s=140','https://q4.qlogo.cn/g?b=qq&nk=345534648&s=140','https:// q4.qlogo.cn/g?b=qq&nk=1473732204&s=140','https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140','https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140','https://q4.qlogo.cn/g?b=qq&nk=546437532&s=140','https://q4.qlogo.cn/g? b=qq&nk=478297268&s=140','https://q4.qlogo.cn/g?b=qq&nk=1045488018&s=140','https://q4.qlogo.cn/g?b=qq&nk=529742452&s=140','https://q4.qlogo.cn/g?b=qq&nk=498356537&s=140','https://q4.qlogo.cn/g?b=qq&nk=1216201256&s=140','https://q4.qlogo.cn/g?b=qq&nk=2420495011&s=140','https://q4.qlogo.cn/g?b=qq&nk=573865240&s=140','https://q4.qlogo.cn/g?b=qq&nk=540779515&s=140','https://q4.qlogo.cn/g?b=qq&nk=576401639&s=140','https://q4.qlogo.cn/g? b=qq&nk=642611305&s=140','https://q4.qlogo.cn/g?b=qq&nk=191036879&s=140','https://q4.qlogo.cn/g?b=qq&nk=309556238&s=140','https://q4.qlogo.cn/g?b=qq&nk=443658608&s=140','https://q4.qlogo.cn/g?b=qq&nk=582238977&s=140','https:// q4.qlogo.cn/g?b=qq&nk=1002876683&s=140','https://q4.qlogo.cn/g?b=qq&nk=790407854&s=140','https://q4.qlogo.cn/g?b=qq&nk=2728566370&s=140','https://q4.qlogo.cn/g?b=qq&nk=380868478&s=140','https://q4.qlogo.cn/g? b=qq&nk=50838724&s=140','https://q4.qlogo.cn/g?b=qq&nk=1204769712&s=140','https://q4.qlogo.cn/g?b=qq&nk=977986117&s=140','https://q4.qlogo.cn/g?b=qq&nk=271094088&s=140','https://q4.qlogo.cn/g?b=qq&nk=842556893&s=140','https:// q4.qlogo.cn/g?b=qq&nk=1307361960&s=140','https://q4.qlogo.cn/g?b=qq&nk=735557314&s=140','https://q4.qlogo.cn/g?b=qq&nk=231637664&s=140','https://q4.qlogo.cn/g?b=qq&nk=450416548&s=140','https://q4.qlogo.cn/g? b=qq&nk=352780148&s=140','https://q4.qlogo.cn/g?b=qq&nk=451770310&s=140','https://q4.qlogo.cn/g?b=qq&nk=29634955&s=140','https://q4.qlogo.cn/g?b=qq&nk=369021828&s=140','https://q4.qlogo.cn/g?b=qq&nk=605130685&s=140','https:// q4.qlogo.cn/g?b=qq&nk=547215440&s=140','https://q4.qlogo.cn/g?b=qq&nk=2758074764&s=140','https://q4.qlogo.cn/g?b=qq&nk=303493454&s=140','https://q4.qlogo.cn/g?b=qq&nk=1097428472&s=140','https://q4.qlogo.cn/g? b=qq&nk=122217907&s=140','https://q4.qlogo.cn/g?b=qq&nk=674429340&s=140','https://q4.qlogo.cn/g?b=qq&nk=964066767&s=140','https://q4.qlogo.cn/g?b=qq&nk=326209638&s=140','https://q4.qlogo.cn/g?b=qq&nk=447830919&s=140','https:// q4.qlogo.cn/g?b=qq&nk=2675525296&s=140','https://q4.qlogo.cn/g?b=qq&nk=38485204&s=140','https://q4.qlogo.cn/g?b=qq&nk=912789481&s=140','https://q4.qlogo.cn/g?b=qq&nk=2332763905&s=140','https://q4.qlogo.cn/g? b=qq&nk=823269956&s=140','https://q4.qlogo.cn/g?b=qq&nk=842167869&s=140','https://q4.qlogo.cn/g?b=qq&nk=16774483&s=140','https://q4.qlogo.cn/g?b=qq&nk=834732600&s=140','https://q4.qlogo.cn/g?b=qq&nk=490895919&s=140','https:// q4.qlogo.cn/g?b=qq&nk=1615626139&s=140','https://q4.qlogo.cn/g?b=qq&nk=38170353&s=140','https://q4.qlogo.cn/g?b=qq&nk=2757286691&s=140','https://q4.qlogo.cn/g?b=qq&nk=526962645&s=140','https://q4.qlogo.cn/g? b=qq&nk=869841650&s=140','https://q4.qlogo.cn/g?b=qq&nk=397031079&s=140','https://q4.qlogo.cn/g?b=qq&nk=1245223999&s=140','https://q4.qlogo.cn/g?b=qq&nk=790038009&s=140','https://q4.qlogo.cn/g?b=qq&nk=623447784&s=140','https://q4.qlogo.cn/g?b=qq&nk=254875515&s=140','https://q4.qlogo.cn/g?b=qq&nk=57100459&s=140','https://q4.qlogo.cn/g?b=qq&nk=3251046152&s=140','https://q4.qlogo.cn/g?b=qq&nk=396990356&s=140','https://q4.qlogo.cn/g? b=qq&nk=460902513&s=140','https://q4.qlogo.cn/g?b=qq&nk=1052718000&s=140','https://q4.qlogo.cn/g?b=qq&nk=1129862709&s=140','https://q4.qlogo.cn/g?b=qq&nk=656450052&s=140','https://q4.qlogo.cn/g?b=qq&nk=849099934&s=140','https://q4.qlogo.cn/g?b=qq&nk=972621860&s=140','https://q4.qlogo.cn/g?b=qq&nk=1072032210&s=140','https://q4.qlogo.cn/g?b=qq&nk=861097570&s=140','https://q4.qlogo.cn/g?b=qq&nk=1670072566&s=140','https://q4.qlogo.cn/g? b=qq&nk=917623040&s=140','https://q4.qlogo.cn/g?b=qq&nk=516902394&s=140','https://q4.qlogo.cn/g?b=qq&nk=382608430&s=140','https://q4.qlogo.cn/g?b=qq&nk=304561494&s=140','https://q4.qlogo.cn/g?b=qq&nk=247545894&s=140','https:// q4.qlogo.cn/g?b=qq&nk=418785462&s=140','https://q4.qlogo.cn/g?b=qq&nk=990042616&s=140','https://q4.qlogo.cn/g?b=qq&nk=595079628&s=140','https://q4.qlogo.cn/g?b=qq&nk=1061982257&s=140','https://q4.qlogo.cn/g? b=qq&nk=875580931&s=140','https://q4.qlogo.cn/g?b=qq&nk=821317585&s=140','https://q4.qlogo.cn/g?b=qq&nk=41833737&s=140','https://q4.qlogo.cn/g?b=qq&nk=170107630&s=140','https://q4.qlogo.cn/g?b=qq&nk=270284132&s=140','https:// q4.qlogo.cn/g?b=qq&nk=401515395&s=140','https://q4.qlogo.cn/g?b=qq&nk=729111761&s=140','https://q4.qlogo.cn/g?b=qq&nk=657172434&s=140','https://q4.qlogo.cn/g?b=qq&nk=707045247&s=140','https://q4.qlogo.cn/g? b=qq&nk=359147214&s=140','https://q4.qlogo.cn/g?b=qq&nk=443142267&s=140','https://q4.qlogo.cn/g?b=qq&nk=2539803416&s=140','https://q4.qlogo.cn/g?b=qq&nk=752641005&s=140','https://q4.qlogo.cn/g?b=qq&nk=498201529&s=140','https://q4.qlogo.cn/g?b=qq&nk=420394884&s=140'] pool=threadpool.ThreadPool(10) #有10个线程 # reqs=[] reqs = threadpool.makeRequests(down_load_pics,urls)#让他给每个线程分配 # [pool.putRequest(req) for req in reqs] for req in reqs: pool.putRequest(req) pool.wait() #等待线程执行结束
print('运行完成')

python的多线程是利用不了多核cpu的
全局解释器锁:GIL
cpu密集型任务:消耗cpu比较多;例如:排序、运算。。
io密集型任务:input/output;写文件、读文件、上传、下载
消耗io处理的-使用多线程
消耗cpu处理的-使用多进程
10、多进程
import multiprocessing import time # lock=multiprocessing.Lock() #也有锁 def make_money(): #也可以在进程里启线程 print('开始挣钱') time.sleep(10) def start_process(): for i in range(5): p=multiprocessing.Process(target=make_money) p.start() print(multiprocessing.active_children()) #获取当前进程数 while len(multiprocessing.active_children())!=1: pass print('运行结束') if __name__ == '__main__': #windows必须写 start_process()

二、单元测试
用于自己测自己写的代码。
单元测试框架
unittest
pytest
1、 unittest
#my_fuction.py def add(a,b): s=a+b return s #------------------------------------------------------------ import unittest import my_fuction class TestAdd(unittest.TestCase): #继承unittest.TestCase def test_add_normal(self): result=my_fuction.add(1,2) self.assertEqual(3,result) def test_add_error1(self): result=my_fuction.add(1,2) self.assertEqual(4,result) def test_add_error2(self): result=my_fuction.add(1,2) self.assertEqual(4,result,'正常整数加法没有通过') if __name__=='__main__': unittest.main()

2、测试报告
1)出报告
import unittest import my_fuction import HTMLTestRunner class TestAdd(unittest.TestCase): #继承unittest.TestCase def test_add_normal(self): result=my_fuction.add(1,2) self.assertEqual(3,result) def test_add_error1(self): result=my_fuction.add(1,2) self.assertEqual(4,result) def test_add_error2(self): result=my_fuction.add(1,2) self.assertEqual(4,result,'正常整数加法没有通过') if __name__=='__main__': test_suite=unittest.TestSuite() test_suite.addTest(TestAdd("test_add_error2")) with open('report.html','wb') as fw: runner = HTMLTestRunner.HTMLTestRunner( stream=fw,title='tmz测试报告', description='天马座接口测试报告', ) runner.run(test_suite)

2)出报告+控制台打印结果
if __name__=='__main__': # unittest.main() #1 无报告 # test_suite=unittest.TestSuite() #2单个运行某个测试用例 # test_suite.addTest(TestAdd("test_add_error1")) #2 # test_suite.addTest(TestAdd("test_add_error2")) #2 #运行某个类里面所有测试用例 test_suite = unittest.makeSuite(TestAdd) with open('report.html','wb') as fw: runner = HTMLTestRunner.HTMLTestRunner( stream=fw,title='tmz测试报告', description='天马座接口测试报告', verbosity=2 #控制台打印结果 ) runner.run(test_suite)

3)有饼状图分析报告
import unittest import my_fuction # import HTMLTestRunner import HTMLTestRunner_PY3 if __name__=='__main__': #运行某个类里面所有测试用例 test_suite = unittest.makeSuite(TestAdd) with open('report.html','wb') as fw: runner = HTMLTestRunner_PY3.HTMLTestRunner( stream=fw, title='tmz测试报告', description='天马座接口测试报告', verbosity=2 ) runner.run(test_suite)

4)报告中加用例描述
import unittest import my_fuction # import HTMLTestRunner import HTMLTestRunner_PY3 class TestAdd(unittest.TestCase): #继承unittest.TestCase '''测试add方法类''' def test_add_normal(self): '''正常测试加法的''' result=my_fuction.add(1,2) self.assertEqual(3,result) def test_add_error1(self): '''测试失败使用''' result=my_fuction.add(1,2) self.assertEqual(4,result) def test_add_error2(self): '''测试失败使用''' result=my_fuction.add(1,2) self.assertEqual(4,result,'正常整数加法没有通过') if __name__=='__main__': #运行某个类里面所有测试用例 test_suite = unittest.makeSuite(TestAdd) with open('report.html','wb') as fw: runner = HTMLTestRunner_PY3.HTMLTestRunner( stream=fw, title='tmz测试报告', description='天马座接口测试报告', verbosity=2 ) runner.run(test_suite)

5)py文件加作者
# -*- coding:utf-8 -*-
# @FileName :${NAME}.py
# @Time :${DATE} ${TIME}
# @Author :niuhanyang
# @Desc :
6)查看git上有谁修改过代码
7)找某个目录下的测试用例
if __name__=='__main__': # 4、查找某个目录下的测试用例 test_suite = unittest.defaultTestLoader.discover('cases', 'test_*.py') with open('report.html', 'wb') as fw: #HTMLTestRunner_PY3 runner = HTMLTestRunner_PY3.HTMLTestRunner( stream=fw, title='tmz测试报告', description='天马座接口测试报告', verbosity=2 ) runner.run(test_suite)


8)参数化
pip install parameterized
import unittest import my_fuction import HTMLTestRunner_PY3 import parameterized class TestAdd(unittest.TestCase): #继承unittest.TestCase '''测试add方法类''' def test_add_normal(self): '''正常测试加法的''' result=my_fuction.add(1,2) self.assertEqual(3,result) def test_add_error1(self): '''测试失败使用''' result=my_fuction.add(1,2) self.assertEqual(4,result) def test_add_error2(self): '''测试失败使用''' result=my_fuction.add(1,2) self.assertEqual(4,result,'正常整数加法没有通过') @parameterized.parameterized.expand( [ [1,2,3], [-1,2,1], [-1,2,2] ] ) def test_param_add(self,a,b,c): result = my_fuction.add(a,b) self.assertEqual(c,result,'预期结果是%s,实际结果是%s'%(c,result)) if __name__=='__main__': #3运行某个类里面所有测试用例 test_suite = unittest.makeSuite(TestAdd) with open('report.html','wb') as fw: #HTMLTestRunner_PY3 runner = HTMLTestRunner_PY3.HTMLTestRunner( stream=fw, title='tmz测试报告', description='天马座接口测试报告', verbosity=2 ) runner.run(test_suite)

step

浙公网安备 33010602011771号