一、插件安装及部署
谷歌驱动:chromedriver.storage.googleapis.com/index.html
1.安装导入unittest模块
pip install unittest
安装完成后可能调用时会存在调用报错的情况,解决方法如下:
file ---> setting ---> Project: ---> Python Interpreter ---> 右边小齿轮 ---> show all ---> 点击加号 ---> Virtualenv Environment ---> 选择New environment ---> Base interpreter选择安装的python.exe
报错是因为cmd安装的在安装python的目录中,新建的项目的vanv中无法使用,可单独在对应项目中的Terminal中采用相同的安装命令安装即可, 是单独拥有的,不会影响cmd已安装的
二、命名规则
1.新建类
必须要继承unittest模块的 unittest.TestCase
class TestCrm(unittest.TestCase):
2.方法测试用例必须以 test_开头
def test_case1(self):
具体示例(Unittest_test.py):
import unittest
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
def test_case1(self):
print('第一个测试用例')
三、运行
1.命令行的形式及对应运行参数
命令行的形式需在下方打印台下选择Terminal
进入对应文件夹 如:cd UnitTest_demo
主要命令为:
python -m unittest
对应参数有:1.接.py文件 2.接类名 3.接方法测试用例 4.添加参数
1.接.py文件
python -m unittest Unittest_test.py
运行文件(Unittest_test.py)下所有方法测试用例
2.接类名
python -m unittest Unittest_test.TestCrm
运行类(TestCrm)下所有方法测试用例
3.接方法测试用例
python -m unittest Unittest_test.TestCrm.test_case1
运行指定方法测试用例
运行结果:
第一个测试用例
.
----------------------------------------------------------------------
Ran 1 test in 0.000sOK
4.1.添加参数 -v
python -m unittest -v unittest_test.py
打印详细的结果,展示是在哪个类哪个方法里的运行结果
运行结果:
test_case1 (Unittest_test.TestCrm) ... 第一个测试用例
更多参数配置参考: unittest --- 单元测试框架 — Python 3.11.8 文档 的命令行接口
2.main方法:unittest.main()
import unittest
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
def test_case1(self):
print('第一个测试用例')
if __name__ == '__main__':
unittest.main()
运行结果:
Ran 1 test in 0.008s
OK
Process finished with exit code 0
第一个测试用例
3.main方法存在的缺点
在使用main方法运行时,除了unittest.main() 被执行,其余语句未被执行
import unittest
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
def test_case1(self):
print('第一个测试用例')
if __name__ == '__main__':
a = 10
print(a)
unittest.main()
运行结果:
Ran 1 test in 0.008s
OK
Process finished with exit code 0
第一个测试用例
由以上例子可知,除了unittest.main() 被执行,其余语句均未被执行
3.1.缺点产生原因
unittest是单元测试框架,__name__ == '__main__'自己运行自己,所以程序自己运行时,会调用当前程序中名字以“test”开头的函数
3.2.解决main时无法运行其他语句方法
因为程序自己运行时,会调用当前程序中名字以“test”开头的函数,所以只需要程序被调用运行即可。
具体解决方法:
1、pycharm--->右上角选择文件下拉框--->点击选择Edit Configurations--->点击加号选择python--->右边Script path:选择要与运行的.py --->点击ok
2、回到对应的.py,点击右上角选择文件下拉框旁边的运行,即可解决
选择文件后点击右上角选择文件下拉框旁边的运行后的结果为
.
----------------------------------------------------------------------
Ran 1 test in 0.000sOK
10
第一个测试用例
3.3.unittest.main()中main的TestProgram的剖析
(ctrl+鼠标左键可查看封装信息)
def __init__(self, module='__main__', defaultTest=None, argv=None,
testRunner=None, testLoader=loader.defaultTestLoader,
exit=True, verbosity=1, failfast=None, catchbreak=None,
buffer=None, warnings=None, *, tb_locals=False):
module:需要执行的方法用例的路径 默认__main__为当前所在.py的方法用例
defaultTest:测试套件 如12.2中指定的 默认为None argv:接收外部参数 testRunner:测试运行器 testLoader:测试加载器 如:12.3中指定的 默认为None exit:程序运行完毕后是否退出 默认为true verbosity:1:默认,显示执行用例的总数以及全局的执行结果,显示对应标记 <0:显示执行用例的总数以及全局的执行结果 >1:显示执行用例的总数以及全局的执行结果,显示对应详细结果 如:第二条4.1加-V的详细信息一致
4.运行顺序
会根据方法参数用例名由前至后的每个字符的ASCII码的顺序执行(ASCII码越前的先执行)
ord('x')可看每个字符的ASCII码
5.运行结果状态
“.” 成功
“F” 失败
“E”报错,异常被抛出
“S”用例未被执行
“OK”成功
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
def test_case1(self):
raise Exception('代码应无法定位中断')
print('第一个测试用例')
运行结果:
Ran 1 test in 0.002s
FAILED (errors=1)
Exception: 代码应无法定位中断
file--tools--python integrated tools -- testing -- Default test runner -- 可以选择是unittest运行还是pytest运行
6.多个unittest测试类或方法测试用例组合运行
6.1.新建多个类多个方法测试用例(Unittest_test.py,Unittest_test2.py)
Unittest_test.py
import unittest
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
def test_case1(self):
print('第一个测试用例')
def test_case2(self):
print('第二个测试用例')
def test_case3(self):
print('第三个测试用例')
Unittest_test2.py
import unittest
class TestCrm2(unittest.TestCase): # 新建类,必须继承unittest.TestCase
def test_case4(self):
print('第四个测试用例')
def test_case5(self):
print('第五个测试用例')
def test_case6(self):
print('第六个测试用例')
6.2.将运行程序封装于新的 unittest_run.py
6.2.1.使用 TestSuite 测试套件:整理测试用例,形成集合
import unittest
from UnitTest_demo.Unittest_test import TestCrm
from UnitTest_demo.Unittest_test2 import TestCrm2
if __name__ == '__main__':
# (用套件的方式)
# 创建一个测试套件
tj = unittest.TestSuite()
# 将方法用例添加到套件(注意导入)
tj.addTest(TestCrm('test_case1'))
tj.addTest(TestCrm('test_case3'))
tj.addTest(TestCrm2('test_case5'))
# 执行(注意要指定套件)
unittest.main(defaultTest='tj')
运行结果:
...
----------------------------------------------------------------------
Ran 3 tests in 0.000sOK
第一个测试用例
第二个测试用例
第五个测试用例
还可以一次添加多个方法测试用例 (addTests)
import unittest
from UnitTest_demo.Unittest_test import TestCrm
from UnitTest_demo.Unittest_test2 import TestCrm2
if __name__ == '__main__':
# (用套件的方式)
# 方法二
# addTests可增加多个
# 创建一个测试套件
tj = unittest.TestSuite()
# 将方法用例添加到套件(注意导入)
List = [TestCrm('test_case1'), TestCrm2('test_case5')]
tj.addTests(List)
# 执行(注意要指定套件)
unittest.main(defaultTest='tj')
运行结果:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000sOK
第一个测试用例
第五个测试用例Process finished with exit code 0
6.2.2.使用TestLoader 测试加载器:加载测试用例或测试用例套件
import unittest
if __name__ == '__main__':
# (用测试加载器的方式)
# zdhtest文件夹下所有前缀带有Unittest_的py
tj = unittest.defaultTestLoader.discover('UnitTest_demo', pattern='Unittest_*.py')
unittest.main(defaultTest='tj')
运行结果:
......
----------------------------------------------------------------------
Ran 6 tests in 0.001sOK
第一个测试用例
第二个测试用例
第三个测试用例
第四个测试用例
第五个测试用例
第六个测试用例Process finished with exit code 0
四、夹具
1.测试用例夹具:
每个用例执行前后先执行(不需要每个用例都加,一个类加一次即可)
setUp/tearDown
import unittest
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
def setUp(self) -> None:
print('方法用例运行前我先运行')
def tearDown(self) -> None:
print('方法用例运行后我会运行')
def test_case1(self):
print('第一个测试用例')
def test_case2(self):
print('第二个测试用例')
if __name__ == '__main__':
unittest.main()
运行结果:
Ran 2 tests in 0.002s
OK
方法用例运行前我先运行
第一个测试用例
方法用例运行后我会运行
方法用例运行前我先运行
第二个测试用例
方法用例运行后我会运行Process finished with exit code 0
2.类夹具:
每个类执行前后先执行(一个class中添加一次)
注意:前后需要加注解@classmethod
setUpClass/tearDownClass
import unittest
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
@classmethod
def setUpClass(cls) -> None:
print('类运行前我先运行')
@classmethod
def tearDownClass(cls) -> None:
print('类运行后我会运行')
def setUp(self) -> None:
print('方法用例运行前我先运行')
def tearDown(self) -> None:
print('方法用例运行后我会运行')
def test_case1(self):
print('第一个测试用例')
def test_case2(self):
print('第二个测试用例')
if __name__ == '__main__':
unittest.main()
运行结果:
类运行前我先运行
Ran 2 tests in 0.002sOK
方法用例运行前我先运行
第一个测试用例
方法用例运行后我会运行
方法用例运行前我先运行
第二个测试用例
方法用例运行后我会运行
类运行后我会运行
3.模块夹具
每个模块执行前后先执行(一个模块需要添加一次即可)
setUpModule/tearDownModule
4.将夹具封装
为了解决多个py或类中需要添加夹具造成代码冗余,可将夹具单独封装,并在测试用例类中进行调用,对此 新增 JiaJv.py
JiaJv.py
import unittest
class Jiajv(unittest.TestCase):
def setUp(self) -> None:
print('每个方法用例执行前都会运行一次')
def tearDown(self) -> None:
print('每个方法用例执行后都会运行一次')
# 注意:class夹具前要加注解@classmethod
@classmethod
def setUpClass(cls) -> None:
print('每个class类执行前都会运行一次')
@classmethod
def tearDownClass(cls) -> None:
print('每个class类执行后都会运行一次')
封装好了以后,每个测试用例的类直接调用即可。 示例如下:
import unittest
from UnitTest_demo.JiaJv import Jiajv
class TestCrm(Jiajv): # 新建类,必须继承unittest.TestCase
def test_case1(self):
print('第一个测试用例')
def test_case2(self):
print('第二个测试用例')
def test_case3(self):
print('第三个测试用例')
if __name__ == '__main__':
unittest.main()
运行结果:
每个class类执行前都会运行一次
每个方法用例执行前都会运行一次
第一个测试用例
每个方法用例执行后都会运行一次
每个方法用例执行前都会运行一次
第二个测试用例
每个方法用例执行后都会运行一次
每个方法用例执行前都会运行一次
第三个测试用例
每个方法用例执行后都会运行一次
每个class类执行后都会运行一次
Ran 3 tests in 0.014sOK
Process finished with exit code 0
注意事项:
1.注意要导入封装文件
from UnitTest_demo.JiaJv import Jiajv
2.原本继承 unittest.TestCase 的类改为继承 Jiajv
class TestCrm(Jiajv):
可能会有疑问:那 unittest.TestCase 咋继承?
解答:因为JiaJv.py的 Jiajv 已继承了 unittest.TestCase ,所以在测试用例类继承了 Jiajv 后,将映射的间接继承了 unittest.TestCase,所以只需要继承Jiajv即可
五、跳过方法测试用例
由于部分场景的需要,可能会出现需要跳过部分测试用例的情况。对此可采用以下方法
1、@unittest.skip(reason="") 无任何判断,直接跳过
2、@unittest.skipIf(a==10,reason="") 判断“a==10”如果为 true 则跳过
3、@unittest.skipUnless(a==10,reason="") 判断“a==10”如果为 flase 则跳过
reason为跳过的原因,原因会打印于控制台
示例如下:
import unittest
class TestCrm(unittest.TestCase): # 新建类,必须继承unittest.TestCase
a = 100
@unittest.skip(reason="这个用例需保持跳过")
def test_case1(self):
print('第一个测试用例')
@unittest.skipUnless(a == 10, reason="当程序未运行到第十次的时候均需要跳过") # a == 10为false 所以会跳过此用例
def test_case2(self):
print('第二个测试用例')
@unittest.skipIf(a == 10, reason="当程序运行第十次的时候需要跳过") # a == 10不为true 所以不会跳过此用例
def test_case3(self):
print('第三个测试用例')
if __name__ == '__main__':
unittest.main()
运行结果:
Ran 3 tests in 0.002s
OK (skipped=2)
Skipped: 这个用例需保持跳过Skipped: 当程序运行第十次的时候需要跳过
第三个测试用例Process finished with exit code 0
六、断言
unittest常用断言如下:(断言函数是内嵌于unittest框架)
1、assertEqual(a, b) 判断a==b是否为true
2、assertNotEqual(a, b) 判断a==b是否为flase
3、assertIn(a, b) 判断a的字段在b中存在为true
4、assertNotIn(a, b) 判断a的字段在b中存在为flase
5、assertTrue(a==b) 判断a==b为true
6、assertFlase(a==b) 判断a==b为flase
7、assertIsNone(a) 判断a为None是true
8、assertIsNotNone(a) 判断a为None是flase
具体示例:def test_case5(self): print('第五个测试用例') self.assertEqual(a, b)
七、测试报告
1.text形式
采用 unittest.TextTestRunner() 可添加 verbosity= 如:unittest.TextTestRunner(verbosity=2)
verbosity可以设置不同的级别
import unittest
if __name__ == '__main__':
# UnitTest_demo文件夹下所有前缀带有Unittest_的py
tj = unittest.defaultTestLoader.discover('UnitTest_demo', pattern='Unittest_*.py')
# 输出报告
yx = unittest.TextTestRunner()
yx.run(tj) # tj可以使用套件也可使用加载
报告会以第二条第5点的形式展示
添加verbosity级别后会以第二条第1点的4.1的形式展示
2.html形式
先pip或者下载HTMLTestRunner.py 放到python路径的Lib文件夹下
import unittest
from HTMLTestRunner import HTMLTestRunner
if __name__ == '__main__':
# UnitTest_demo文件夹下所有前缀带有Unittest_的py
tj = unittest.defaultTestLoader.discover('UnitTest_demo', pattern='Unittest_*.py')
# 报告存放位置
file = open('./zdhtest/report.html', 'wb') # wb可读写
# 输出报告(stream:生成的文件存放位置 title:测试报告标题 description:报告的描述 )
yx = HTMLTestRunner(stream=file, title='测试报告', description='执行情况如下:')
yx.run(tj) # tj可以使用套件也可使用加载