版权声明:本文为CSDN博主「药药君」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Static_at/article/details/82840337
基础
unittest是python自带的一个测试框架,也称单元测试。
使用时必须导入unittest模块。
#coding:utf-8
import unittest
class MathTestCase(unittest.TestCase):#定义一个类,继承unittest.TestCase
def testSub(self): ## test method names begin 'test*' 告诉我们写函数时要以test开头
self.assertEqual(2-1,1) #assertEqual表示断言,2-1的预期结果是1
self.assertEqual((3-3),0)
def testDiv(self):
self.assertEqual(2/1,2)
self.assertEqual((3/2),1.5)
if __name__=="__main__":
unittest.main()
运行结果:
总结:
1.单元测试需要导入包 import unittest
2.类必须继承unittest.testCase
3.构建的函数必须以test关键字开头
4.运行所有函数使用 unittest.main()
5.断言使用 self.assertEqual()
setUp()和tearDown()应用
setUp:表示前置条件,它在每一个用例执行之前必须会执行一次
setUp可以理解为我们需要自动化测试时,需要打开网页窗口,输入对应测试地址,这一些属于前置条件。
tearDown:表示释放资源,它在每次用例执行完之后会执行一次
tearDown可以理解为我们测试完毕后,需要关闭浏览器。
以下示例演示setUp和tearDown的执行顺序:
#coding:utf-8
from selenium import webdriver
import unittest
from time import sleep
class Baidu_search(unittest.TestCase):
def setUp(self):
self.bro=webdriver.Firefox()
self.bro.maximize_window()
self.bro.get("https://www.baidu.com")
sleep(1)
def tearDown(self):
sleep(1)
self.bro.quit()
def test_search2(self): #代码运行顺序和函数名相关
self.bro.find_element_by_id("kw").send_keys(u"第二次单元测试")
self.bro.find_element_by_id("su").click()
sleep(1)
def test_search1(self):
self.bro.find_element_by_id("kw").send_keys(u"第一次单元测试")
self.bro.find_element_by_id("su").click()
sleep(1)
if __name__=="__main__":
unittest.main()
跳过执行某个测试用例的方法
概括
@unittest.skip(reason):强制跳转。reason是跳转原因
@unittest.skipIf(condition, reason):condition为True的时候跳转
@unittest.skipUnless(condition, reason):condition为False的时候跳转
@unittest.expectedFailure:如果test失败了,这个test不计入失败的case数目
self.skipTest(reason):一般写在函数体内部
代码示例(以bilibili登录为例)
from selenium import webdriver
import unittest
from time import sleep
class LoginTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get('https://passport.bilibili.com/login')
sleep(2)
def tearDown(self):
sleep(2)
self.driver.quit()
def testLogin01(self):
self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('autotest') #注意修改账号密码
self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('123456')
self.driver.find_element_by_xpath("//a[text()='登录']").click()
@unittest.skip('用户名密码都为空,测试用例不执行')
def testLogin02(self):
username = self.driver.find_element_by_xpath("//input[@id='login-username']").text
password = self.driver.find_element_by_xpath("//input[@id='login-passwd']").text
self.assertEqual(username, '用户名不为空')
self.assertEqual(password, '密码不为空')
#
@unittest.skipIf(3 > 2, '3大于2,测试用例不执行')
def testLogin03(self):
self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('autotest')
self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('123456')
self.driver.find_element_by_xpath("//a[text()='登录']").click()
sleep(2)
self.driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
co = self.driver.find_element_by_xpath("//div[@class='text-con']/p/span[2]").text
self.assertEqual(co, '网络文化经营许可证 沪网文【2019】3804-274号')
#
"""
这个用例不进行注释,其他test代码就不会执行,会直接执行这个
@unittest.skipUnless(3<2, '2>3不执行测试用例')
# @unittest.expectedFailure
def testLogin04(self):
self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('autotest')
self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('123123')
self.driver.find_element_by_xpath("//a[text()='登录']").click()
err_info = self.driver.find_element_by_xpath("//div/p[text()='账号或密码错误']").text
self.assertEqual(err_info, '账号或密码错误')"""
def testLogin05(self):
self.skipTest('通过skipTest跳过这个测试用例')
self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('autotest')
self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('123456')
self.driver.find_element_by_xpath("//a[text()='登录']").click()
if __name__ == '__main__':
unittest.main()
1. @unittest.skipUnless()装饰器和其他代码一起运行时,其他test代码不执行
2. @unittest.skipUnless()内容注释后
批量运行测试用例
test01的代码:
#coding:utf-8
class LoginTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get('https://passport.bilibili.com/login')
sleep(2)
def tearDown(self):
sleep(2)
self.driver.quit()
def testLogin01(self):
self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('15755189711')
self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('2bqingnian')
self.driver.find_element_by_xpath("//a[text()='登录']").click()
@unittest.skip('用户名密码都为空,测试用例不执行')
def testLogin02(self):
username = self.driver.find_element_by_xpath("//input[@id='login-username']").text
password = self.driver.find_element_by_xpath("//input[@id='login-passwd']").text
self.assertEqual(username, '用户名不为空')
self.assertEqual(password, '密码不为空')
#
@unittest.skipIf(3 > 2, '3大于2,测试用例不执行')
def testLogin03(self):
self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('15755189711')
self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('2bqingnian')
self.driver.find_element_by_xpath("//a[text()='登录']").click()
sleep(2)
self.driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
co = self.driver.find_element_by_xpath("//div[@class='text-con']/p/span[2]").text
self.assertEqual(co, '网络文化经营许可证 沪网文【2019】3804-274号')
# @unittest.skipUnless(3<2, '2>3不执行测试用例')
# # @unittest.expectedFailure
# def testLogin04(self):
# self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('15755189711')
# self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('2fyuqsdttgna')
# self.driver.find_element_by_xpath("//a[text()='登录']").click()
# err_info = self.driver.find_element_by_xpath("//div/p[text()='账号或密码错误']").text
# self.assertEqual(err_info, '账号或密码错误')
def testLogin05(self):
self.skipTest('通过skipTest跳过这个测试用例')
self.driver.find_element_by_xpath("//input[@id='login-username']").send_keys('15755189711')
self.driver.find_element_by_xpath("//input[@id='login-passwd']").send_keys('2bqingnina')
self.driver.find_element_by_xpath("//a[text()='登录']").click()
if __name__ == '__main__':
unittest.main()
在单元测试中批量运行测试用例的方法有两种。
第一种是通过手动添加,通过unittest.Testsuite来管理用例集,通过addTest添加用例方法,再通过实例化TextTestrunner运行测试。
第二种是通过自动识别用例的目录对所有的用例进行运行。使用到discover()函数。
首先来演示第一种手动添加写法:创建一个test_air.py
#coding:utf-8
import unittest
from baidu_search import Baidu_search
class Xseq(unittest.TestCase):
@classmethod
def setUpClass(cls):
print "前置测试条件"
@classmethod
def tearDownClass(cls):
print "结束测试条件"
def testadd(self):
print '1+1=',1+1
def testsub2(self):
print '3-2=',3-2
def testsub1(self):
print '3-3=',3-3
if __name__=="__main__":
suite = unittest.TestSuite() #实例化用例集
suite.addTest(Xseq("testsub1")) #把testsub1测试用例添加到用例集
suite.addTest(Xseq("testsub2"))
#suite.addTest(Baidu_search("test_search2"))
runner = unittest.TextTestRunner() #实例化运行类
runner.run(suite) #运行用例集,会根据添加的用例顺序进行用例的执行
# unittest.main()#运行所有函数
总结:
实例化用例集: 用例集对象名 = unittest.TestSuite()
添加用例到用力集写法: 用例集对象名.addTest(类名(“函数名”))
实例化运行类: 运行对象名 = unittest.TextTestRunner()
运行用例集: 运行对象名.run(用例集对象名)
在有很多用例需要运行的时候,不可能一个个用例手动过去添加。
或是用例函数方法名改变之后,也不可能每一个添加用例的地方都要去修改,这里就需要用到第二个方法,通过路径去识别用例,从而去实现执行用例的方法。
第二种自动识别路径去运行的方法演示:
import unittest
import os
def allrun():
test_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)))#获取当前工作目录
# test_dir = os.path.join(os.path.dirname(os.path.realpath('E:\project\untitled\test_devlopment')))#获取当前工作目录
#用discover的方法去覆盖所有的测试用例
# test_dir 要执行的测试用例目录
# test*表示匹配以test开头的所有.py文件
# top_level_dir=None 测试模块的顶级目录,没有的话就写None
discover = unittest.defaultTestLoader.discover(test_dir,pattern="test*.py",top_level_dir=None)
runner = unittest.TextTestRunner() #实例化runner类
runner.run(discover) #执行路径中匹配的所有test*.py用例
allrun()
运行结果:
总结:
在获取系统目录时需要加入os模块,os模块是对系统操作时必须存在的。当前目录使用过的os方法请前往python os模块
导入os模块: import os
获取当前工作目录: 目录对象名 = os.path.join(os.path.dirname(os.path.realpath(file)))
用discover()函数覆盖测试用例方法:
用例集对象名 = unittest.defaultTestLoader.discover(目录对象名,pattern=“test*.py”,top_level_dir=None)
实例化运行类 : 运行对象名 = unittest.TextTestRunner()
执行所有匹配的测试用例: 运行对象名.run(用例集对象名)
封装discover加载测试用例方法
把用例和这个封装的方法都放在一个工作目录下。
封装一个discover方法可以直接在这个方法写执行所有匹配的测试用例。
#coding:utf-8
import unittest
import os
def Run_all_test():
#实例化覆盖对象,匹配test*.py的文件
case_dir = os.path.join(os.path.dirname(os.path.realpath(__file__))) # 获取当前工作目录(用例也放在该目录下)
discover = unittest.defaultTestLoader.discover(case_dir,"test*.py",top_level_dir=None)
return discover #返回实例化对象(用例集)
if __name__=="__main__":
runner = unittest.TextTestRunner() #实例化运行类
runner.run(Run_all_test()) #执行所有的匹配用例集
生成测试报告并发送到邮件
unittest单元测试不支持直接生成测试报告,因此测试报告都是通过第三方模块来进行导出。
而第三方库导出的测试报告呈现以HTML形式,而第三方模块名称为 HTMLTestRunner
下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html
1.图下选择红框里的HTMLTestRunner.py,打开后把网页另存为即可下载。
2.下载好后把HTMLTestRunner.py放到python的Lib目录下即可
在使用的时候导入HTMLTestRunner包即可。
以下为代码演示(其中封装好的发送邮件模块,请点击Send_email查阅)
#coding:utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8') #以上三行是python2.x版本需要加入,不然会报错
from selenium import webdriver
import unittest
import os
from HTMLTestRunner import HTMLTestRunner
from time import sleep
from Send_email import send_email #导入已封装好的发送邮件模块
class Baidu_search(unittest.TestCase):
def setUp(self):
self.bro = webdriver.Chrome()
self.bro.maximize_window()
self.bro.get("https://www.baidu.com")
sleep(1)
def tearDown(self):
sleep(1)
self.bro.quit()
def test_search2(self):
self.bro.find_element_by_id("kw").send_keys(u"第二次单元测试")
self.bro.find_element_by_id("su").click()
sleep(1)
def test_search1(self):
self.bro.find_element_by_id("kw").send_keys(u"第一次单元测试")
self.bro.find_element_by_id("su").click()
sleep(1)
if __name__ == "__main__":
# 获取当前工作目录:
test_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)))
#默认加载覆盖当前目录下的test匹配的测试用例:
discover = unittest.defaultTestLoader.discover(test_dir,pattern="test*.py",top_level_dir=None)
#测试报告保存路径:保存在当前目录,以result.hmtl为名保存,该名可以随意取
test_report = os.path.join(os.path.dirname(os.path.realpath(__file__)),"result.html")
#通过打开文件流,以二进制的格式写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件:
fp = open(test_report,"wb")
#实例化测试报告对象,其中有三个参数,stream表示文件流,title表示测试报告标题,description表示测试报告描述:
runner = HTMLTestRunner(stream=fp,title=u"我是测试报告标题",description="我是测试报告描述")
runner.run(discover) #执行测试用例
fp.close() #关闭数据流才会生成测试报告
send_email() #发送测试报告到指定邮件
总结:
-
使用HTMLTestRunner必须导入包:from HTMLTestRunner import HTMLTestRunner
-
测试报告保存路径写法: 测试报告文件名 = os.path.join(os.path.dirname(os.path.realpath(file)),“result.html”)
-
打开文件流,写入报告: fp = open(测试报告文件名,“wb”)
-
实例化测试报告对象: 测试报告对象名 = HTMLTestRunner(steam=fp,title=“测试的报告标题”,description=“测试的报告描述”)
-
关闭文件数据流: fp.close()