1.junit 和unittest框架
- 相同点:都是单元测试
- junit (java)是白盒测试,unittest(pathon)是黑盒测试
2.unittest框架简介
1.unittest 是python 的单元测试框架,提供了创建测试用例,测试套件以及批量执行的方案, 2.unittest 在安装pyhton 以后就直接自带了,直接import unittest 就可以使用。 3.作为单元测试的框架, unittest 也是可以对程序最小模块的一种敏捷化的测试。利用单元测试框架,创建一个类,该类继承unittest的TestCase,这样可以把每个case看成是一个最小的单元, 由测试容器组织起来,到时候直接执行,同时引入测试报告.
3.unittest框架的构成
-
test fixture(测试固件): 做一些测试过程中必须要有的东西初始化和清理测试环境,比如创建临时的数据库,文件和目录等,其中 setUp() 【初始化】和 TearDown()【UI功能测试后的清理】是最常用的方法 每个测试用例执行的时候,setUp() 和 TearDown()都会执行 -
test case(单元测试用例),以 test_开头,TestCase 是编写单元测试用例最常用的类 -== test suite(测试套件)==:单元测试用例的集合,把不同测试用例组合一起执行。 -
test runner:执行单元测试 -
== test report==:生成测试报告
class TestCase(unittest.TestCase):
def setUp(self):
print("开始执行用例")
def test_1(self):
print("用例1")
def test_2(self):
print("用例2")
def tearDown(self):
print("用例执行结束")
if __name__ == '__main__':
unittest.main()
from selenium import webdriver
import unittest
import time
class Baidu1(unittest.TestCase):
def setUp(self):
print(".......setup........")
self.driver=webdriver.Chrome();
self.url="http://www.baidu.com/"
self.driver.maximize_window()
def tearDown(self):
print("........teardown......")
self.driver.quit()
def test_hao(self):
driver=self.driver
driver.get(self.url)
time.sleep(3)
driver.find_element_by_link_text("hao123").click()
time.sleep(6)
def test_baiduSearch(self):
driver=self.driver
driver.get(self.url)
time.sleep(3)
driver.find_element_by_id("kw").send_keys("张艺兴")
driver.find_element_by_id("su").click()
time.sleep(6)
if __name__ == "__main__":
unittest.main(verbosity=1)
'''
可以增加verbosity参数,例如unittest.main(verbosity=2)
在主函数中,直接调用main() ,在main中加入verbosity=2 ,这样测试的结果就会显示的更加详细。
这里的verbosity 是一个选项, 表示测试结果的信息复杂度,有三个值:
0 ( 静默模式): 你只能获得总的测试用例数和总的结果比如总共100个失败,20 成功80
1 ( 默认模式): 非常类似静默模式只是在每个成功的用例前面有个“ . ” 每个失败的用例前面有个“F”
2 ( 详细模式): 测试结果会显示每个测试用例的所有相关的信息
'''
4.批量执行测试脚本(构建测试套件)
开发人员通常都需要编写多个测试用例才能对某一软件功能进行比较完整的测试,这些相关的测试用例称为一个测试用例集。,在unittest中是用TestSuite 类来表示的
假设我们已经编写了testbaidu1.py,testbaidu2.py两个文件,那么我们怎么同时执行这两个文件呢 testbaidu1.py
from selenium import webdriver
import unittest
import time
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()
def test_hao(self):
driver=self.driver
driver.get(self.url)
time.sleep(6)
print(driver.title)
self.assertNotEqual(driver.title, "百度一下,你就知道", msg="不相等!")
driver.find_element_by_link_text("hao123").click()
time.sleep(6)
def test_baidusearch(self):
driver=self.driver
driver.get(self.url)
time.sleep(3)
driver.find_element_by_id("kw").send_keys("张艺兴")
driver.find_element_by_id("su").click()
self.assertTrue("hello"=="heeell", msg="not equal!")
time.sleep(6)
def is_element_present(self, how, what):
try:
self.driver.find_element(by=how, value=what)
except NoSuchElementException as e:
return False
return True
def is_alert_present(self):
try:
self.driver.switch_to.alert
except NoAlertPresentException as e:
return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to.alert
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
if __name__=="__main__":
unittest.main(verbosity=1)
from selenium import webdriver
import unittest
import time
from selenium.common.exceptions import NoAlertPresentException
from selenium.common.exceptions import NoSuchElementException
class Baidu2 (unittest.TestCase) :
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.driver.maximize_window()
self.verificationErrors=[]
self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
def test_hao(self):
driver = self.driver
driver.get(self.base_url)
driver.find_element_by_link_text("新闻").click()
time.sleep(6)
self.assertTrue("123" == "1234", msg="not true")
time.sleep(3)
def test_baidusearch(self):
driver = self.driver
driver.get(self.base_url)
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(u"张艺兴")
driver.find_element_by_id("su").click()
time.sleep(6)
self.assertNotEqual("张艺兴_搜索", driver.title, msg="网页未打开!")
self.assertTrue("张艺兴_搜索" == driver.title, msg="表达式不相等!")
time.sleep(6)
def is_element_present(self, how, what):
try:
self.driver.find_element(by=how, value=what)
except NoSuchElementException as e:
return False
return True
def is_alert_present(self):
try:
self.driver.switch_to.alert
except NoAlertPresentException as e:
return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to.alert
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
if __name__ == "__main__":
unittest.main(verbosity=2)
4.1 第一种方法 addTest():把测试用例一个一个添加到脚本中
当有多个或者几百测试用例的时候, 这样就需要一个测试容器( 测试套件) ,把测试用例放在测试套件进行执行,unittest 模块中提供了TestSuite 类来生成测试套件,使用该类的构造函数可以生成一个测试套件的实例,该类提供了addTest来把每个测试用例加入到测试套件中。
runall.py
import unittest
import testbaidu1
import testbaidu2
def createsuite():
suite=unittest.TestSuite()
suite.addTest(testbaidu1.Baidu1("test_hao"))
suite.addTest(testbaidu1.Baidu1("test_baidusearch"))
suite.addTest(testbaidu2.Baidu2("test_hao"))
suite.addTest(testbaidu2.Baidu2("test_baidusearch"))
return suite
if __name__=="__main__":
suite = createsuite()
unittest.TextTestRunner(verbosity=1).run(suite)
addTest()的缺点
1.需要导入所有的py文件,比如import testbaidu1,每新增一个需要导入一个 2.addTest需要增加所有的testcase,如果一个py文件中有10个case,就需要增加10次
4.2 第二种makeSuite():类添加,把一个测试脚本中的所有测试用例添加到测试套件中
在unittest 框架中提供了makeSuite() 的方法,makeSuite可以实现把测试用例类内所有的测试case组成的测试套件TestSuite ,unittest 调用makeSuite的时候,只需要把测试类名称传入即可。
import unittest
import testbaidu1
import testbaidu2
def createsuite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(testbaidu1.Baidu1))
suite.addTest(unittest.makeSuite(testbaidu2.Baidu2))
return suite
if __name__=="__main__":
suite = createsuite()
unittest.TextTestRunner(verbosity=1).run(suite)
4.3 第三种TestLoader()的应用:类添加,把一个测试脚本中的所有测试用例添加到测试套件中
TestLoader 用于创建类和模块的测试套件,只需要把测试类名称传入即可。一般的情况下,使TestLoader().loadTestsFromTestCase(TestClass)来加载测试类
import unittest
import testbaidu1
import testbaidu2
def createsuite():
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=1)
runner.run(suite)
4.4 第四种discover()执行文件夹下面的所有测试用例**
import unittest
import testbaidu1
import testbaidu2
def createsuite():
discover = unittest.defaultTestLoader.discover("../src0716", pattern="testbaidu*.py", top_level_dir=None)
print(discover)
return discover
if __name__=="__main__":
suite = createsuite()
unittest.TextTestRunner(verbosity=1).run(suite)
5.用例的执行顺序
unittest 框架默认加载测试用例的顺序是根据ASCII 码的顺序,数字与字母的顺序为: 0~9 AZ,az 。
忽略某用例的执行
在用例前面加上@unittest.skip(“skipping”)
6.unittest断言(预判结果是否正确)
自动化的测试中, 对于每个单独的case来说,一个case的执行结果中, 必然会有期望结果与实际结果,在unittest 的库中提供了大量的实用方法来检查预期值与实际值, 来验证case的结果。
下面例子相等,所以直接运行成功 下面例子不相等,则运行失败,输出msg中的内容
也可以在 IDE(录制脚本)中生成断言
7…HTML报告生成
脚本执行完毕之后,还需要看到HTML报告, 下面我们就通过HTMLTestRunner.py 来生成测试报告(百度云中有) ,下载后将其放在此目录下。
import time
import unittest
def createsuite():
discovers = unittest.defaultTestLoader.discover("../src0716", pattern="testbaidu*.py", top_level_dir=None)
print(discovers)
return discovers
if __name__=="__main__":
curpath = sys.path[0]
print(sys.path)
print(sys.path[0])
if not os.path.exists(curpath+'/resultreport'):
os.makedirs(curpath+'/resultreport')
now = time.strftime("%Y-%m-%d-%H %M %S", time.localtime(time.time()))
print(time.time())
print(time.localtime(time.time()))
filename = curpath + '/resultreport/'+ now + 'resultreport.html'
with open(filename, 'wb') as fp:
runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u"测试报告",
description=u"用例执行情况", verbosity=2)
suite = createsuite()
runner.run(suite)
生成html测试报告
8.异常捕捉与错误截图
定义一个函数 1.捕捉错误截图的存储位置 2.解决重复命名的问题 3.截图
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(3)
from selenium import webdriver
import unittest
import time
import os
class Baidu1(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.verificationErrors=[]
self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([],self.verificationErrors)
def test_baidu(self):
driver = self.driver
driver.get(self.base_url)
driver.maximize_window()
time.sleep(6)
print(driver.title)
try:
self.assertEqual(u"dddd百度一下,你就知道", driver.title)
except:
self.saveScreenShot(driver, "hao.png")
time.sleep(5)
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(3)
if __name__ == "__main__":
unittest.main()
9.数据驱动(ddt)
参考添加链接描述 将测试数据和代码分开写
pip install ddt
- dd.ddt:
装饰类,也就是继承自TestCase的类。 - ddt.data:
装饰测试方法。参数是一系列的值。 - ddt.file_data:
装饰测试方法。参数是文件名。文件可以是json 或者 yaml类型。 注意,如果文件以”.yml”或者”.yaml”结尾,ddt会作为yaml类型处理,其他所有文件都会作为json文件处理。如果文件中是列表,每个列表的值会作为测试用例参数,同时作为测试用例方法名后缀显示。如果文件中是字典,字典的key会作为测试用例方法的后缀显示,字典的值会作为测试用例参数。 - ddt.unpack:
传递的是复杂的数据结构时使用。比如使用元组或者列表,添加unpack之后,ddt会自动把元组或者列表对应到多 个参数上。字典也可以这样处理。
rom selenium import webdriver
import unittest
import time
from ddt import ddt, unpack, data, file_data
import sys, csv
def getCsv(file_name):
rows = []
path = sys.path[0]
with open(path+'/data/'+file_name, 'rt') as f:
readers = csv.reader(f, delimiter=',', quotechar='|')
next(readers, None)
for row in readers:
temprows=[]
for i in row:
temprows.append(i)
rows.append(temprows)
return rows
@ddt
class Baidu1(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(30)
self.base_url = "http://www.baidu.com/"
self.driver.maximize_window()
self.verificationErrors=[]
self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([],self.verificationErrors)
@file_data('test_baidu_data.json')
def test_baidu1(self, value):
driver = self.driver
driver.get(self.base_url + "/")
driver.maximize_window()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
time.sleep(3)
@unittest.skip("skipping")
@data(*getCsv('test_baidu_data.txt'))
@unpack
def test_baidu2(self, value, expected_value):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(value)
driver.find_element_by_id("su").click()
driver.maximize_window()
time.sleep(6)
self.assertEqual(expected_value, driver.title, msg="和预期搜索结果不一致!")
print(expected_value)
print(driver.title)
time.sleep(6)
if __name__ == '__main__':
unittest.main()
|