书签
一、unittest模块的核心属性
二、五大要素
三、TestCase
四、TestSuite及TestRunner
五、TestLoader
六、Fixture
七、UnitTest断言
八、参数化
九、跳过
十、生成HTML 测试报告
前言
UnitTest是python内置的单元测试框架,具备编写用例、组织用例、执行用例、输出报告等自动化框架的条件。
一、unittest模块的核心属性
unittest.TestCase:TestCase类,所有测试用例类继承的基本类。
class Test01(unittest.TestCase):
unittest.main():使用她可以方便的将一个单元测试模块变为可直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中以“test”命名开头的测试方法,并自动执行他们。执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。所以以A开头的测试用例方法会优先执行,以a开头会后执行。
unittest.TestSuite():unittest框架的TestSuite()类是用来创建测试套件的。
unittest.TextTextRunner():unittest框架的TextTextRunner()类,通过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。
unittest.defaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动根据测试目录start_dir匹配查找测试用例文件(test*.py),并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover。用法如下:
discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
unittest.skip():装饰器,当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。一种常见的用法就是比如说想调试某一个测试用例,想先屏蔽其他用例就可以用装饰器屏蔽。
二、五大要素
- TestCase(测试用例)
- TestSuite(测试套件)
- TestRunner(以文本的形式运行测试用例)
- TestLoader(批量执行测试用例-搜索指定文件夹内指定字母开头的模块)
- Fixture(固定装置----两个固定的函数,一个初始化时使用,一个结束时使用)
三、TestCase
TestCase就是测试用例。
(一) 案例
定义一个实现加法操作的函数,并对该函数进行测试
(二) 定义测试用例
- 导包:import unittest
- 定义测试类:新建测试类必须继承unittest.TestCase
- 定义测试方法:测试方法名称命名必须以test开头(可在 TestLoader(object)类中修改 testMethodPrefix = 'test’的值。)
(三) 执行测试用例
方式一:
使用pycharm在代码上点击鼠标右键,选择使用UnitTest运行
(注意点击位置是Class处还是def处,点击Class处运行则Class下所有test都会执行)
方式二:
调用 unittest.main() 来运行
## test01.py
import unittest
def add(x,y):
return x+y
class Test01(unittest.TestCase):
def test_add(self):
result = add(1,1)
print("结果为:",result)
def test_add2(self):
result = add(1,2)
print("结果为:",result)
if __name__ == '__main__':
unittest.main()
四、TestSuite及TestRunner
多条测试用例集合在一起,就是一个TestSuite。
(一) TestSuite使用方法
-
实例化: suite = unittest.TestSuite()
(suite:为TestSuite实例化的名称) -
添加用例:suite.addTest(ClassName(“MethodName”))
(ClassName:为类名;MethodName:为方法名) -
添加所有:suite.addTest(unittest.makeSuite(ClassName))
(搜索指定ClassName内test开头的方法并添加到测试套件中) -
执行
TestSuite需要配合TestRunner才能被执行。
TextTestRunner是用来执行测试用例和测试套件的
使用:
runner = unittest.TextTestRunner() #实例化
runner.run(suite) # 执行,suite:为测试套件名称
#示例
import unittest
from test01 import Test01
suite = unittest.TestSuite()#实例化
suite.addTest(Test01("test_add"))# 添加一个用例
suite.addTest(unittest.makeSuite(Test01))#批量添加
# 执行
runner = unittest.TextTestRunner()
runner.run(suite)
五、TestLoader
用来加载TestCase到TestSuite中,即加载满足条件的测试用例,并把测试用例封装成测试套件。
(一)思路
使用unittest.TestLoader(),通过该类下面的discover()方法自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件;
(二)用法
suite = unittest.TestLoader().discover(test_dir, pattern='test*.py')
# test_dir: 为指定的测试用例的目录
# pattern:为查找的.py文件的格式,默认为'test*.py'
自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件。
也可以使用unittest.defaultTestLoader 代替 unittest.TestLoader()。
注: 在底层defaultTestLoader是TestLoader()的实例化,所以无括号。
defaultTestLoader = TestLoader()
运行:
runner = unittest.TextTestRunner().run(suite)
# 实例化 && 执行
(三)TestLoader与TestSuite区别
- TestSuite需要手动添加测试用例(可以添加测试类,也可以添加测试类中某个测试方法)
- TestLoader搜索指定目录下指定开头.py文件,并添加测试类中的所有的测试方法,不能指定添加测试方
法;
六、Fixture
Fixture是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture。
(一)Fixture控制级别
- 方法级别
- 类级别
- 模块级别
(二)方法级别
使用:
-
初始化(前置处理):
def setUp(self) --> 首先自动执行。 -
销毁(后置处理):
def tearDown(self) --> 最后自动执行。 -
运行于测试方法的始末,即:运行一次测试方法就会运行一次setUp和tearDown
(三)类级别
使用:
- 初始化(前置处理):
@classmethod
def setUpClass(cls): --> 首先自动执行 - 销毁(后置处理):
@classmethod
def tearDownClass(cls): --> 最后自动执行 - 运行于测试类的始末,即:每个测试类只会运行一次setUpClass和tearDownClass
(四)模块级别 [了解]
使用:
- 初始化(前置处理):
def setUpModule() --> 首先自动执行 - 销毁(后置处理):
def tearDownModule() --> 最后自动执行 - 运行于整个模块的始末,即:整个模块只会运行一次setUpModule和tearDownModule
(五)案例
需求:使用UnitTest框架对tpshop项目测试
1). 点击登录,进入登录页面
2). 输入用户名和密码,不输入验证码,直接点击登录按钮
3). 获取错误提示信息
import time
import unittest
from time import sleep
from selenium import webdriver
from parameterized import parameterized
class TestTpshopLogin(unittest.TestCase):
#初始化
def setUp(self):
# 获取浏览器驱动对象
self.driver =webdriver.Chrome()
#打开url
url ='http://www.tpshop.com'
self.driver.get(url)
#最大化
self.driver.maximize_window()
#隐式等待
self.driver.implicitly_wait(30)
def tearDown(self):
#关闭浏览器驱动
sleep(5)
self.driver.quit()
def test_login_code_null(self):
driver = self.driver
# 点击登录页面
driver.find_element_by_link_text("登录").click()
# 输入用户名
driver.find_element_by_id("username").send_keys("11234567843")
# 输入密码
driver.find_element_by_name("password").send_keys("23615115")
# 点击登录按钮
driver.find_element_by_name("sbtbutton").click()
# 获取页面错误信息
result = driver.find_element_by_css_selector(".layui-layer-padding").text
print("result:",result)
expect_result ="验证码不能为空!!"
try:
# 断言
self.assertEqual(expect_result,result)
except AssertionError:
# 截图
driver.get_screenshot_as_file("./{}.png".format(time.strftime("%Y_%m_%d_%H_%M_%S")))
# 抛出异常
raise
(六)总结
- 必须继承unittest.TestCase类,setUp、tearDown才是一个Fixture
- setUp:一般做初始化工作,比如:实例化浏览器驱动对象、浏览器最大化、设置隐式等待等
- tearDown:一般做结束工作,比如:关闭浏览器驱动对象、退出登录等
七、UnitTest断言
让程序代替人为判断测试程序执行结果是否符合预期结果的过程就是断言
(一)UnitTest断言方法(常用)
断言方法 | 断言描述 |
---|---|
assertTrue(expr, msg=None) | 验证expr是true,如果为false,则fail |
assertFalse(expr,msg=None) | 验证expr是false,如果为true,则fail |
assertEqual(arg1, arg2,msg=None) | 验证arg1=arg2,不等则fail |
assertNotEqual(arg1, arg2,msg=None) | 验证arg1 != arg2, 相等则fail |
assertIn(arg1, arg2,msg=None) | 验证arg1是arg2的子串,不是则fail |
assertNotIn(arg1, arg2, msg=None) | 验证arg1不是arg2的子串,是则fail |
assertIsNone(expr, msg=None) | 验证expr是None,不是则fail |
assertIsNotNone(expr, msg=None) | 验证expr不是None,是则fail |
assertIs(arg1, arg2, msg=None) | 验证arg1、arg2是同一个对象,不是则fail |
(二)使用方法
断言方法已经封装在unittest.TestCase类中,直接调用
import unittest
def add(x,y):
return x+y
class Test01(unittest.TestCase):
def test_add(self):
result = add(1,1)
self.assertEqual(result,3,"错误")
### AssertionError: 2 != 3 : 错误
(三)Python自带的三种断言
- 判断两个字符串是否相等
assert a == b (msg=None)
assert “hello” == "hello" "相等"
- 判断第二个字符串是否包含第一个字符串
assert a in b (msg=None)
assert "he" in "hello" "包含"
- 判断是否为True/False
# True
assert True (msg=None)
assert 1 (msg=None)
# False
assert False (msg=None)
assert 0 (msg=None)
八、参数化
通过参数的方式来传递数据,从而实现数据和脚本分离。并且可以实现用例的重复执行。
(一)安装扩展包—parameterized
unittest测试框架,本身不支持参数化,但是可以通过安装unittest扩展插件parameterized来实现。
pip install parameterized
(二)使用方式
导包:from parameterized import parameterized
使用@parameterized.expand装饰器可以为测试函数的参数进行参数化
注:
- @parameterized.expand 接收 列表数据(列表嵌套元组)。
- 测试方法定义变量时需对应每一种参数。
# 方式一 :参数直接使用
@parameterized.expand([(1,), ( 0,), (3,)])
def test_add(self, x):
pass
# 方式二:参数先命名在代入 @parameterized.expand
data = [(1, 1, 2), (1, 0, 1), (0, 0, 0)]
@parameterized.expand(data)
def test_add(self, x, y, expect):
pass
# 方式三:构建一个参数方法再代入@parameterized.expand
def build_data():
return [(1, 1, 2), (1, 0, 1), (0, 0, 0)]
@parameterized.expand(build_data)
def test_add(self, x, y, expect):
result = add(x,y)
assert result == expect
九、跳过
对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行。
(一)使用方式
- 直接将测试函数标记成跳过
@unittest.skip('代码未完成')
- 根据条件判断测试函数是否跳过
@unittest.skipIf(condition, reason)
注:以上两种方法都可修饰类和方法
(二)例子
#例子
import unittest
version = 6
class TestAdd(unittest.TestCase):
@unittest.skip('test_01代码未完成')
def test_01(self):
# 功能未实现
print("test_01被执行")
@unittest.skipIf(version > 5,'test_02代码未完成')
def test_02(self):
# 功能未实现
print("test_02被执行")
十、生成HTML 测试报告
(一)报告生成原理
把控制台信息写入TXT。
import unittest
suite = unittest.defaultTestLoader.discover("./",pattern="test01*.py")
with open("./reprot.txt","w",encoding="utf8") as f:
unittest.TextTestRunner(stream=f ,descriptions="test",verbosity=3).run(suite)
(二)HTML 测试报告
导入扩展文件HTMLTestRunner.py(根据 TextTestRunner 改编而来,下载地址)
操作:
- 导包
from HTMLTestRunner import HTMLTestRunner
- 定义测试套件
suite = unittest.defaultTestLoader.discover("../case", pattern="test*.py")
- 实例化 HTMLTestRunner 类,并调用 run 方法执行测试套件。
with open(报告存放路径, "wb") as f: #注意:生成 html 报告,必须使用 wb,以二进制形式写入
HTMLTestRunner(stream=f,).run(测试套件) # 实例化 HTMLTestRunner 类
# stream为必须参数,title、description等其余参数可ctrl+p查看选用
参考链接
https://www.cnblogs.com/yufeihlf/p/5707929.html