参考博文
一、unittest框架解析
unittest 单元测试提供了创建测试用例,测试套件以及批量执行的方案, unittest 在安装pyhton 以后就直接自带了,直接import unittest 就可以使用。
** unittest 对程序最小模块(类或者方法)的一种敏捷化的测试。**
单元测试:针对程序模块中进行正确性校验的测试工作(特点:应用中的最小可测单元、测试执行速度快、发现问题,更容易定位,一般由开发人员进行,也即是白盒测试)
在自动化测试中,我们不需要做白盒测试。利用单元测试框架,创建一个类,继承unittest的TestCase,这样可以把每个case看成是一个最小的单元, 由测试容器组织起来,直接执行,同时引入测试报告。
单元unittest框架:针对UI界面的功能进行自动化测试。不同于Java和Junit单元测试框架
unittest的5个重要概念
unittest 各组件的关系为:
- test fixture(测试固件):即测试环境的搭建。比如创建临时的数据库,文件和目录等。一般通过初始化(前置)和清理测试环境(结束)实现。 1. setUp():测试用例执行前的准备:如环境、数据等2. setDown():测试环境的清理操作,如关闭浏览器等
- test case:测试用例(def test_add()),TestCase 是编写单元测试用例最常用的类:一个测试用例就是一个完成的测试单元,需执行setup()--->run()---->setDown()
- test suite:测试用例的集合集,TestSuite 是最常用的类 1. addTest(): 把单个测试用例一个一个的放进测试用例集合里2. makeSuit(): 把一个类里的所有测试用例添加到一个测试套件里3. TestLoader(): 同上4. discover(): 把一个确定的文件夹下,以某种形式命名文件中的所有测试用例形成一个测试套件
- test runner:执行测试用例
- test loader:生成测试报告
unittest的用例规则:
- 1、测试文件必须导包:import unittest
- 2、测试类必须继承 类:unittest.TestCase
- 3、测试方法必须以 test_开头
TestCase类中的几个特殊方法:
- setUp():测试前的初始化工作(所有测试用例开始前都会执行的)
- tearDown():测试后的清理工作
- setUpClass():@classmethod,在所有测试方法运行前执行,只会执行一遍
- tearDownClass():@classmethod,在所有测试方法运行结束后执行,只会执行一遍
1.1测试用例的编写及代码
类代码cal.py:
class Math1:
def __init__(self,a,b):
self.a = int(a)
self.b = int(b)
def add(self):
return self.a + self.b
def sub(self):
return self.a - self.b
测试代码:
from cal import Math1
import unittest
# from selenium import webdriver
#创建测试用例的类TestMath,必须继承类unittest.TestCase
class TestMath(unittest.TestCase):
#----------------------测试前的初始化工作---------------------#
@classmethod #加上修饰,说明是类的修饰,只在类里执行,因为只有一个集合类,所以只执行一遍
def setUpClass(cls):
print("setUpClass")
def setUp(self):
print("setUp") #两条测试用例都会执行,执行两次
#----------------------测试用例的编写---------------------#
def test_add(self):
j = Math1(4,3)
self.assertEqual(j.add(),7 )
def test_sub(self):
i = Math1(26,5)
self.assertEqual(i.sub(), 21)
#----------------------测试后的结束工作---------------------#
def tearDown(self):
print("tearDown") #两条测试用例都会执行,执行两次
@classmethod
def tearDownClass(cls):
print("tearDownClass")
#----------------------测试用例的执行---------------------#
if __name__ == "__main__":
#构造测试集:放入所有测试用例 :此处表示由两个测试用例组成的测试集
suite = unittest.TestSuite()
suite.addTest(TestMath('test_add')) #将单个测试用例放入测试用例集合中
suite.addTest(TestMath('test_sub'))
#执行测试用例
runner = unittest.TextTestRunner() #调用方法
runner.run(suite) #直接执行测试用例集
1.2断言
断言:测试用例实际结果与预期结果的对比
测试用例的要素:测试环境、测试步骤、输入、实际结果、预期结果
unittest 的单元测试库中常用的断言方法:
1.3用例的执行顺序
默认执行规则:测试类或测试方法的数字语字母顺序:0-9,A-Z,a-z(先执行完一个类中的方法,才会执行下一个类)
忽略测试用例的执行:@unittest.skip("skipping")
1.4测试用例综合管理框架
测试综合管理框架包括:
1.StartEnd.py : 开始和结束工作:setUp 和tearDown
2.cal.py: 加减法实现,整体功能模块
3.test_add.py:单个功能测试用例
4.test_sub.py:单个功能测试用例
5.run.py:用例执行
**F:**用例出现缺陷
.:成功
E:脚本中出现错误
1)StartEnd.py:
import unittest
class setUp_tearDown(unittest.TestCase):
def setUp(self):
print("开始测试")
def tearDown(self):
print("测试结束")
2)cal.py: 加减法实现,整体功能模块
class Math1:
def __init__(self,a,b):
self.a = int(a)
self.b = int(b)
def add(self):
return self.a + self.b
def sub(self):
return self.a - self.b
3)test_add.py:单个功能测试用例
from cal import *
from StartEnd import *
class Test_add(setUp_tearDown):
def test_add(self):
j = Math1(5,9)
self.assertEqual(j.add(),14)
def test_addError(self):
j = Math1(5,9)
self.assertNotEqual(j.add(),6)
4)test_sub.py:单个功能测试用例
from StartEnd import *
from cal import *
class Test_sub(setUp_tearDown):
def test_sub(self):
i = Math1(48,45)
self.assertEqual(i.sub(),3)
5)run.py
import unittest
test_dir = './'
#批量执行当前测试用例
discovery = unittest.defaultTestLoader.discover(test_dir,pattern="test*.py")
if __name__ == "__main__":
runner = unittest.TextTestRunner()
runner.run(discovery)
6)完整的测试代码:使用了unittest框架的脚本
from selenium import webdriver
import unittest
import time
import os
from selenium.common.exceptions import NoAlertPresentException
from selenium.common.exceptions import NoSuchElementException
class Baidu1(unittest.TestCase):
def setUp(self): #初始化环境,测试开始前执行的操作
print("-----setUp-----")
self.driver = webdriver.Chrome()
self.url = "https://www.baidu.com/"
self.driver.maximize_window()
time.sleep(3)
def tearDown(self): #测试结束后清理环境
print("--------tearDown--------")
self.driver.quit() #关闭浏览器
#--------------测试用例 test_hao 和test_hao -------#
# 每个测试用例执行时都会执行开始和结束操作:setup
#忽略测试用例的执行: @unittest.skip("skipping")
def test_hao(self):
driver = self.driver
url = self.url
driver.get(url)
driver.find_element_by_link_text("hao123").click() #定位到百度页面的超链接“hao123”,也可以定位到“新闻”等其他超链接
time.sleep(6)
def test_hbaidu(self):
driver = self.driver
url = self.url
driver.get(url)
# self.assertTrue("百度一下,你就知道" == driver.title, msg="不一致!!!")
driver.find_element_by_id("kw").send_keys("告白气球")
driver.find_element_by_id("su").submit()
time.sleep(3)
print(driver.title)
try:
self.assertNotEqual(driver.title,"告白气球_百度搜索",msg="实际结果与预期结果不一致")
except:
self.saveScreenAsPhoto(driver,"haohao.png")
time.sleep(3)
def saveScreenAsPhoto(self,driver,file_name):
if not os.path.exists("./images"):
os.makedirs("./images")
now = time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time()))
driver.get_screenshot_as_file("./images/" + now + "-" + file_name)
if __name__ == "__main__":
unittest.main() #执行所有测试用例(类中的所有方法)
unittest提供了全局的main()方法:使用它可以方便地将一个单元测试模块变成可以直接运行的测试脚本。main()方法搜索所有包含在该模块中以”test"命名的测试方法,并自动执行他们。
1)跑测试用例套件的步骤:此前提是要先把单个测试用例添加到套件里
- 先生成测试套件: suite = creatSuit()
- 得到跑测试套件的runner:runner = unittest.TextTestRunner(verbosity=2)
- 用runner跑套件:runner.run(suite)
import unittest
from src0716 import testbaidu1
from src0716 import testbaidu2
def createsuite():
#addTest
suite = unittest.TestSuite()
suite.addTest(testbaidu1.Baidu1("test_hao")) #添加测试文件中的测试用例,此方法只能一个一个添加
suite.addTest(testbaidu1.Baidu1("test_hbaidu"))
suite.addTest(testbaidu2.Baidu2("test_hao"))
suite.addTest(testbaidu2.Baidu2("test_baidusearch"))
return suite
if __name__=="__main__":
suite = createsuite()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
1.5makeSuite()、TestLoader()、discover()的应用
makeSuite:把一个测试用例类里的所有测试用例case组成测试套件TestSuite
TestLoader :创建类和模块的测试套件,使TestLoader().loadTestsFromTestCase(TestClass) 来加载测试类。
discover :通过递归方式到其子目录中从指定的目录开始, 找到所有测试模块并返回包含它们对象的TestSuite ,然后加载与模式匹配唯一的测试文件,discover(dir,pattern,top_level_dir=None)
(1)把一个类里的测试用例添加到套件间里,代码如下:
import unittest,csv
import os,sys
import time
import testbaidu1
import testbaidu2
#手工添加案例到套件,
def createsuite():
suite = unittest.TestSuite()
#将测试用例加入到测试容器(套件)中
suite.addTest(unittest.makeSuite(testbaidu1.Baidu1))
suite.addTest(unittest.makeSuite(testbaidu2.Baidu2))
return suite
'''
suite1 = unittest.TestLoader().loadTestsFromTestCase(testbaidu1.Baidu1)
suite2 = unittest.TestLoader().loadTestsFromTestCase(testbaidu2.Baidu2)
suite = unittest.TestSuite([suite1, suite2])
return suite
'''
if __name__=="__main__":
suite=createsuite()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
(2)把一个文件夹下以某种形式命名(正则表达式匹配)的所有文件的测试用例都加载到测试套件:
import unittest,csv
import os,sys
import time
#手工添加案例到套件,
def createsuite():
discover=unittest.defaultTestLoader.discover('../test',pattern='test*.py',top_le
vel_dir=None)
print discover
return discover
if __name__=="__main__":
suite=createsuite()
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
1.6HTML报告生成
1)添加HTMLTestRunner.py文件:C:\Users\HY\AppData\Local\Programs\Python\Python38\lib
2)HTML报告的生成步骤:
解决HTML文件存放问题--->创建文件夹
HTML报告命名问题(动态命名,使每个文件名不一样)
# -*- coding: utf-8 -*-
import unittest,csv
import os,sys
import time
import HTMLTestRunner
#手工添加案例到套件,
def createsuite():
discover=unittest.defaultTestLoader.discover('../test',pattern='test*.py',top_level_dir=None)
print(discover)
return discover
if __name__=="__main__":
curpath=sys.path[0]
#取当前时间
now=time.strftime("%Y-%m-%d-%H %M %S",time.localtime(time.time()))
if not os.path.exists(curpath+'/resultreport'):
os.makedirs(curpath+'/resultreport')
filename=curpath+'/resultreport/'+now+'resultreport.html'
with open(filename,'wb') as fp:
#出html报告
runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title=u'测试报告',description=u'用例执行情况',verbosity=2)
suite=createsuite()
runner.run(suite)
1.7错误截图
关键语句:driver.get_screenshot_as_file()
def savescreenshot(self,driver,file_name):
if not os.path.exists('./image'):
os.makedirs('./image')
now=time.strftime("%Y%m%d-%H%M%S",time.localtime(time.time()))
#截图保存
driver.get_screenshot_as_file('./image/'+now+'-'+file_name)
time.sleep
1.8数据驱动
@data :支持一个或者多个数据的传入
@unpack :多个数据传入需对一组数据进行映射,包括:测试数据和测试方法的映射
@file_data:测试数据在json文件中,和测试方法中的参数进行映射
版权归原作者 小河鱼磨洋工 所有, 如有侵权,请联系我们删除。