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 
posted @ 2020-10-24 21:49  白羽归楼  阅读(444)  评论(0)    收藏  举报