unittest是python内置的单元测试框架,具备编写用例、组织用例、执行用例、功能,可以结合selenium进行UI自动化测试,也可以结合appium、requests等模块做其它自动化测试。
testcase
testcase:一个完整的测试单元,执行该测试单元可以完成对某一个问题的验证,完整体现在测试前环境准备(setUp),执行测试代码(run),以及测试后环境还原(tearDown);
testsuite
testsuite:多个测试用例的集合,测试套件或测试计划;
testLoader
testLoader:加载TestCase到TestSuite中的,其中loadTestsFrom__()方法用于寻找TestCase,并创建它们的实例,然后添加到TestSuite中,返回TestSuite实例;
testrunner
testrunner:执行测试用例,并将测试结果保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息;
testfixture
testfixture:一个测试用例的初始化准备及环境还原,主要是setUp()和setDown()方法
a) 用import语句引入unittest模块
b) 让所有执行测试的类都继承于TestCase类,可以将TestCase看成是对特定类进行测试的方法的集合
c) setUp()方法中进行测试前的初始化工作,teardown()方法中执行测试后的清除工作,它们都是TestCase中的方法
d) 编写测试的方法最好以test开头(可以直接运行)deftest_add(self)、deftest_sub(self)等,可以编写多个测试用例对被测对象进行测试
e) 在编写测试方法过程中,使用TestCaseclass提供的方法测试功能点,比如:assertEqual等
f) 调用unittest.main()方法运行所有以test开头的方法
断言即进行预期结果和实际结果比对。
assertEqual(a,b) a==b #是否相等
assertNotEqual(a,b) a!=b #是否不相等
assertTrue(x) bool(x) is True #是否为True
assertFalse(x) bool(x) is False #是否为False
assertIn(a,b) a in b #是否包含
assertGreater(a,b) a>b #大于
assertGreaterEqual(a,b) a >= b #大于等于
assertLess(a,b) a
assertLessEqual(a,b) a<=b #小于等于
# -*- coding: utf-8 -*-
# @Time : 2021/12/30 14:24
# @Author : Limusen
# @File : unittest_demo_14
import unittest
class TestCase01(unittest.TestCase):
def setUp(self) -> None:
print("执行前置")
def tearDown(self) -> None:
print("执行后置信息")
def test_case01(self):
'''加法'''
self.assertEqual(1 + 2, 3)
def test_case02(self):
self.assertEqual(1 + 2, 2)
if __name__ == "__main__":
TestCase01().test_case01()
# -*- coding: utf-8 -*-
# @Time : 2021/12/30 14:35
# @Author : Limusen
# @File : unittest_demo_15
# 断言练习
import time
import unittest
class TestCase02(unittest.TestCase):
def setUp(self) -> None:
# print("执行前置")
pass
def tearDown(self) -> None:
# print("执行后置信息")
pass
def test_case01(self):
a = 1 == 1
self.assertTrue(a, '断言失败,不是True')
# def test_case02(self):
# a =1 ==3
# self.assertTrue(a,'断言失败,不是True')
def test_case03(self):
str = "你有梦想吗"
self.assertTrue(str.__contains__("梦想"))
def test_case04(self):
name = ['张三', '李四', '王五']
self.assertIn('李四', name)
print("范围测试")
def test_case05(self):
self.assertIsInstance('lishou', str)
print("类型判定")
if __name__ == "__main__":
unittest.main()
当在一个测试类或多个测试模块下,用例数量较多时,unittest在执行用例(test_xxx)时,并不是按从上到下的顺序执行,有特定的顺序。
unittest框架默认根据ACSII码的顺序加载测试用例,数字与字母的顺序为:09,AZ,a~z。
对于类来说
classTestAxx会优先于classTestBxx被执行。
对于方法来说
test_aaa()方法会有优先于test_bbb()被执行。对于测试目录与测试文件来说,unittest同样是按照这个规则来加载测试用例的。
方式一
通过addTest()添加用例的顺序控制用例执行
import unittest
class TestCase03(unittest.TestCase):
def setUp(self) -> None:
print("执行前置")
def tearDown(self) -> None:
print("执行后置信息")
def test_case_ccc(self):
print("执行用例:test_ccc")
def test_case_aaa(self):
print("执行用例:test_aaa")
if __name__ == "__main__":
# unittest.main()
# 改变执行顺序方法
suite = unittest.TestSuite()
suite.addTest(TestCase03('test_aaa'))
suite.addTest(TestCase03('test_ccc'))
unittest.main(defaultTest='suite')
方式二
顺应unittest的默认执行顺序,通过设置测试类或者测试方法方法名字来实现
# -*- coding: utf-8 -*-
# @Time : 2021/12/30 14:35
# @Author : Limusen
# @File : unittest_demo_15
import unittest
class TestCase03(unittest.TestCase):
def setUp(self) -> None:
print("执行前置")
def tearDown(self) -> None:
print("执行后置信息")
def test_case_ccc(self):
print("执行用例:test_ccc")
def test_case_aaa(self):
print("执行用例:test_aaa")
def test_case01_aaa(self):
print("执行用例:test_aaa")
def test_case02_ddd(self):
print("执行用例:test_ddd")
def test_case03_ccc(self):
print("执行用例:test_ccc")
def test_case04_bbb(self):
print("执行用例:test_bbb")
if __name__ == "__main__":
# unittest.main()
# # 改变执行顺序方法
# suite = unittest.TestSuite()
# suite.addTest(TestCase03('test_aaa'))
# suite.addTest(TestCase03('test_ccc'))
# unittest.main(defaultTest='suite')
# # 改名字 test_case04_bbb
unittest.main()
在执行测试脚本的时候,可能会有某几条用例本次不想执行,但又不想删也不想注释,unittest通过忽略部分测试用例不执行的方式,分无条件忽略和有条件忽略,通过装饰器实现所描述的场景。
提供的装饰器如下:
@unittest.skip(reason):强制跳转。reason是跳转原因
@unittest.skipIf(condition,reason):condition为True的时候跳转
@unittest.skipUnless(condition,reason):condition为False的时候跳转
@unittest.expectedFailure:标记该测试预期为失败,如果该测试方法运行失败,则该测试不算做失败
# -*- coding: utf-8 -*-
# @Time : 2021/12/30 14:35
# @Author : Limusen
# @File : unittest_demo_15
import unittest
class TestCase04(unittest.TestCase):
def test_case01(self):
print("正在运算test_case01")
self.assertEqual(3 + 4, 7, "求和失败")
@unittest.skip("无条件跳过")
def test_case02(self):
print("正在运算test_case02")
self.assertEqual(4 + 4, 8, "求和失败")
@unittest.skipIf(True, '条件为真跳过')
def test_case03(self):
print("正在运算test_case03")
self.assertEqual(4 + 4, 8, "求和失败")
@unittest.skipIf(False, '条件为假不跳过')
def test_case04(self):
print("正在运算test_case04")
self.assertEqual(4 + 4, 9, "求和失败")
@unittest.skipUnless(False, '条件为假跳过')
def test_case05(self):
print("正在运算test_case05")
self.assertEqual(4 + 4, 9, "求和失败")
@unittest.expectedFailure # 失败不记录失败数量
def test_case06(self):
print("正在运算test_case06")
self.assertEqual(4 + 4, 9, "求和失败")
@unittest.expectedFailure
def test_case07(self):
print("正在运算test_case07")
self.assertEqual(4 + 4, 9, "求和失败")
if __name__ == "__main__":
unittest.main()
在实际项目中,随着项目进度的开展,测试类会越来越多,可是直到现在我们还只会一个一个的单独运行测试类,这在实际项目实践中肯定是不可行的,在unittest中可以通过测试套件来解决该问题。
测试套件(TestSuite)是由多个测试用例(TestCase)组成的,当然也可以由多个子测试套件组成。
在unittest中,把测试用例加载到测试套件的方式有如下方法:
方式一
用unittest.TestSuite()实例化测试套件对象后,内部的addTest()方法对测试类内部的测试案例进行逐一添加。
挑选几个单独执行
# -*- coding: utf-8 -*-
# @Time : 2022/1/6 14:14
# @Author : Limusen
# @File : unittest_demo_20
import unittest
class TestCaseDemo20(unittest.TestCase):
def setUp(self) -> None:
print("执行前置")
def tearDown(self) -> None:
print("执行后置信息")
def test_case_ccc(self):
print("执行用例:test_ccc")
def test_case_aaa(self):
print("执行用例:test_aaa")
def test_case_ddd(self):
print("执行用例:test_ddd")
def test_case_bbb(self):
print("执行用例:test_bbb")
if __name__ == "__main__":
suite = unittest.TestSuite()
suite.addTest(TestCaseDemo20('test_case_ccc'))
suite.addTest(TestCaseDemo20('test_case_bbb'))
unittest.main(defaultTest='suite')
方法二
当测试用例存放在多个不同子目录下,我们用之前的把用例加载到测试集合中的方式还是不太方便,需要不断的去导入和添加测试用例模块,此时可以通过discover()方法来实现。
unittest_discover.py
# -*- coding: utf-8 -*-
# @Time : 2022/1/6 14:14
# @Author : Limusen
# @File : unittest_discover.py
import os
import unittest
case_path = os.path.dirname(os.path.abspath(__file__))
def get_all_case():
discover = unittest.defaultTestLoader.discover(start_dir=case_path,# 测试用例的地址
pattern="unittest_demo_20.py", # 以什么样的文件名去搜索
top_level_dir=None)
suite = unittest.TestSuite()
suite.addTest(discover)
return suite
if __name__ == '__main__':
suite = get_all_case()
unittest.main(defaultTest="suite")
使用第三方HTMLTestRunner执行测试用例集,它可以输出网页版测试报告。HTMLTestRunner是Python标准库的unittest模块的一个扩展,在使用该模块之前要下载HTMLTestRunner.py文件,并将该文件保存在python安装路径下的lib文件夹或者是项目的子包中,在python代码中通过importHTMLTestRunner导入,即可使用。
# -*- coding: utf-8 -*-
# @Time : 2022/1/6 14:14
# @Author : Limusen
# @File : unittest_html.py
import os
import unittest
from common import HTMLTestReportCN
case_path = os.path.dirname(os.path.abspath(__file__))
def get_all_case():
discover = unittest.defaultTestLoader.discover(start_dir=case_path, # 测试用例的地址
pattern="unittest_demo_20.py", # 以什么样的文件名去搜索
top_level_dir=None)
suite = unittest.TestSuite()
suite.addTest(discover)
report_dir = HTMLTestReportCN.ReportDirectory("D:\PythonSelenium\\reports\\")
report_dir.create_dir("ui自动化测试报告")
report_path = HTMLTestReportCN.GlobalMsg.get_value('report_path')
dir_path = HTMLTestReportCN.GlobalMsg.get_value('dir_path')
fp = open(report_path, 'wb')
runner = HTMLTestReportCN.HTMLTestRunner(stream=fp,
title="ui自动化",
description="测试一下",
tester="li")
runner.run(suite)
if __name__ == '__main__':
get_all_case()
今天主要分享的是unittest的基本操作,以及整个流程,从组装测试用例到用例执行的流程,这个面试的时候还是会问的比较多的,主要记住的是unittest如何收集测试用例,采用discover收集,然后怎么创建对象去收集,引入第三方报告还是使用unittest自己的报告等;
地址 : https://gitee.com/todayisgoodday/PythonSelenium
https://www.cnblogs.com/yushengaqingzhijiao/category/2000515.html