测试框架
基于 Python 语言的自动化测试框架 最知名的 有如下 3 款 测试框架:unittest,pytest,robotframework
前两款框架主要(或者说很大程度上)是 聚焦 在 白盒单元测试
而 robotframework 主要聚焦在 系统测试。
unittest
- 定义class使用Test开头,继承unittest.TestCase
- 定义test开头的方法
演示代码
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestCase(unittest.TestCase):
driver = None
def testPass(self):
driver = webdriver.Edge(r'C:\Users\sj176\Downloads\edgedriver_win64\msedgedriver.exe')
self.driver = driver
self.driver.get('https://www.baidu.com')
运行方式
取决于右上角的运行环境,点击右键运行它默认会使用unittest环境运行,如果使用main运行则会走main方法否则不走
unittest运行用例的一个很大的坑:
- 命令行方式运行:python -m unittest 模块名.py 执行整个模块,或者使用python -m unittest 模块名.方法名执行某个方法
- main方式运行:建议再另写一个文件,写:
import unittest
if __name__ == '__main__':
print('------------------')
unittest.main()
Unittest框架
概念UnitTest是Python自带的一个单元测试框架,用它来做单元测试.
自带的框架:不需要安装,直接导报使用即可
第三方框架如果想使用需要进行安装如pytest
对于测试来说,unittest框架的作用是自动化脚本(用例代码)执行框架(使用unittest框架来管理 运行 多个测试用例)
- 为什么使用UnitTest框架
- 能够组织多个用例去执行
- 提供丰富的断言方法
- 能够生成测试报告
- UnitTest核心要素
- TestCase测试用例 最基本的操作用例
- TestSuite测试套件 用来管理,组装,打包TestCase用例的
- TestRunner测试执行,用来执行TestSuite(测试套件)
- TestLoader测试加载,功能是对TestSuite(测试套件)功能的补充
- Fixture测试夹具,书写在TestCase测试用例代码中,是一种代码结构,可以在每个方法前后都会执行的内容
TestCase测试用例
是一个代码文件,在代码文件中来书写真正的用例代码
代码文件名必须按照标识符的规则来书写
步骤:
- 导报(unittest)
- 定义测试类
- 在测试类中书写测试方法,方法名必须以test_开头
- 运行测试用例
代码:
import unittest
class TestDemo(unittest.TestCase):
def test_method1(self):
print('测试方法1')
def test_method2(self):
print('测试方法2')
def test_method3(self):
print('测试方法2')
# 执行方法,点击执行按钮或者输入
TestSuite和TestRunner
使用步骤
- 导报(unittest)
- 实例化(创建对象)套件对象
- 使用套件对象添加用例方法
- 实例化运行对象
- 使用运行对象执行套件对象
代码
方式一:
使用方法进行执行
import unittest
from Test1.SeleniumD import TestDemo
suite=unittest.TestSuite()
suite.addTest(TestDemo('test_method1'))
suite.addTest(TestDemo('test_method2'))
runner=unittest.TextTestRunner()
runner.run(suite)
方式二:
使用对象进行执行
import unittest
from Test1.SeleniumD import TestDemo
from Test1.SeleniumD2 import TestDemo2
suite=unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestDemo))
suite.addTest(unittest.makeSuite(TestDemo2))
runner=unittest.TextTestRunner()
runner.run(suite)
结果打印
.......
----------------------------------------------------------------------
Ran 7 tests in 0.000s
OK
测试方法1
测试方法1
测试方法2
测试方法3
测试方法11
测试方法22
测试方法33
其中.代表用例通过,F用例不通过,E用例代码有问题异常了
TestLoader(测试加载)
使用步骤
- 导包
- 实例化测试加载对象并添加用例--->得到的是suite对象
- 实例化运行对象
- 运行对象执行套件对象
代码实现
import unittest
# unittest.TestLoader().discover('用例所在的路径','用例的代码文件名')
suite=unittest.TestLoader().discover('./Test1','Se*.py')
runner=unittest.TextTestRunner()
runner.run(suite)
执行./Test1目录下的Se*.py测试文件
Fixture(测试夹具)
方法级别
在每个测试方法前后执行一次
class TestDemo2(unittest.TestCase):
def setUp(self) -> None:
print("setUp")
def tearDown(self) -> None:
print("tearDown")
def test_method1(self):
print('测试方法11')
def test_method2(self):
print('测试方法22')
def test_method3(self):
print('测试方法33')
结果:
setUp
测试方法11
tearDown
setUp
测试方法22
tearDown
setUp
测试方法33
类级别
在每个class前后执行一次
class TestDemo2(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
print('setUpClass')
@classmethod
def tearDownClass(cls) -> None:
print('tearDownClass')
def test_method1(self):
print('测试方法11')
def test_method2(self):
print('测试方法22')
def test_method3(self):
print('测试方法33')
结果:
setUpClass
测试方法11
测试方法22
测试方法33
tearDownClass
模块级别
在每个代码文件前后执行一次
import unittest
def setUpModule():
print('setupModule')
# 执行方法,点击执行按钮或者输入
def tearDownModule():
print('teardownModule')
class TestDemo2(unittest.TestCase):
def test_method1(self):
print('测试方法11')
def test_method2(self):
print('测试方法22')
def test_method3(self):
print('测试方法33')
class TestDemo3(unittest.TestCase):
def test_method1(self):
print('测试方法11')
def test_method2(self):
print('测试方法22')
def test_method3(self):
print('测试方法33')
结果:
setupModule
测试方法11
测试方法22
测试方法33
测试方法11
测试方法22
测试方法33
teardownModule
断言
什么是断言:让机器替代人来判断结果是否正确,断言结果:True,False
断言方法
- assertTrue(expr,msg=None):验证expr是true,如果为false,则false
- assertFalse(expr,msg=None):验证expr是false,如果为true,则false
- assertEqual(expr,msg=None):验证expr是==actual,不等于则false
- assertNotEqual(expr,msg=None):验证expr是!=actual相等则false
- assertNone(expr,msg=None):验证expr是None,不是则false
- assertNotNone(expr,msg=None):验证expr不是None,是则false
- assertIn(expr,container,msg=None):验证是否expr in container
- assertNotIn(expr,msg=None):验证是否expr not in container
assertIn('admin','adminnnnnn') 包含
assertIn('admin','ad1minnnnnn') 不包含
代码使用
class TestDemo2(unittest.TestCase):
def test_method1(self):
self.assertEqual('登录成功','登录成功啦')
def test_method2(self):
self.assertIn('登录成功','登录成功啦')
def test_method3(self):
self.assertEqual('登录成功','登录成功')
点击运行按钮运行如果想看测试报告可以点击控制台,左上角有个导出报告按钮,点击导出即可;
参数化
unittest框架本身是不支持参数化,要想使用参数化,需要安装插件来完成
需要安装pip install parameterized
如何验证是否安装成功使用pip list 查看是否存在
使用步骤
- 导包
- 定义测试类
- 书写测试方法(用到的测试数据使用变量代替)
- 组织测试数据并传参
代码
import unittest
from parameterized import parameterized
data=[
('登录成功','登录成功'),
('登录成功', '登录成功'),
('登录成功', '登录成功1'),
]
class TestLogin(unittest.TestCase):
@parameterized.expand(data)
def testLogin1(self,expect,retal):
self.assertEqual(expect,retal)
结果:
C:\Users\sj176\AppData\Local\Programs\Python\Python310\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.2\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --target SeleniumD2.py::TestLogin
Testing started at 22:16 ...
Launching pytest with arguments SeleniumD2.py::TestLogin --no-header --no-summary -q in C:\Users\sj176\PycharmProjects\Demo3\Test1
============================= test session starts =============================
collecting ... collected 3 items
SeleniumD2.py::TestLogin::testLogin1_0__
SeleniumD2.py::TestLogin::testLogin1_1__
SeleniumD2.py::TestLogin::testLogin1_2__ PASSED [ 33%]PASSED [ 66%]FAILED [100%]
SeleniumD2.py:11 (TestLogin.testLogin1_2__)
'登录成功1' != '登录成功'
Expected :'登录成功'
Actual :'登录成功1'
<Click to see difference>
a = (<SeleniumD2.TestLogin testMethod=testLogin1_2__>,)
@wraps(func)
def standalone_func(*a):
> return func(*(a + p.args), **p.kwargs)
..\..\..\AppData\Local\Programs\Python\Python310\lib\site-packages\parameterized\parameterized.py:533: AssertionError
========================= 1 failed, 2 passed in 0.07s =========================
Process finished with exit code 1
跳过
对于一些未完成的或者不满足的测试条件的测试函数和测试类,不想执行,可以使用跳过装饰器来完成跳过该函数或这测试类
直接跳过
@unittest.skip('跳过原因')
根据条件判断是否跳过,判断条件成立-跳过
@unittest.skipIf('判断条件','跳过的原因')
import unittest
version=111
class TestDemo(unittest.TestCase):
@unittest.skip('这个测试方法不能使用了')
def test_method1(self):
print('测试方法1')
@unittest.skipIf(version>=30,'版本号大于等于30不用测试')
def test_method2(self):
print('测试方法2')
def test_method3(self):
print('测试方法3')
# 执行方法,点击执行按钮或者输入
测试报告
自带的测试报告
只有单独运行TestCase的代码才会生成测试报告
生成第三方的测试报告
安装pip install BeautifulReport
安装完成后注意如果使用右键执行不会输出测试报告应为执行方式是unittest需要使用python进行执行
python SeleniumD.py
# time :2021/1/22 15:29
# Author :Maynard
from BeautifulReport import BeautifulReport # 需要导入BeautifulReport
import unittest
class TestDemoCase(unittest.TestCase):
def setUp(self) -> None:
pass
def tearDown(self) -> None:
pass
def testassertdemo(self):
self.assertEqual(1, 1)
def suite():
# 创建一个测试套件
suite = unittest.TestSuite()
# 将测试用例加载到测试套件中
loader = unittest.TestLoader() # 创建一个用例加载对象
suite.addTest(loader.loadTestsFromTestCase(TestDemoCase))
return suite
if __name__ == '__main__':
br = BeautifulReport(suite())
br.report(filename='testdemoreport.html',description='测试报告',log_path='.',report_dir='.')