简介:
Unittest 是一个单元测试框架。以面向对象的方式提供了以下概念:
- test fixture 测试夹具 # 表示执行一个或多个测试所需要的测试,以及任何相关的清除动作
- test case 测试用例 # 测试用例是测试的各个单元。它检查对特定输入集的特定响应
- test suite 测试套件 # 一个测试套件是测试案例,测试套件,或两者的集合。它用于聚合应该一起执行的测试
- test runner 测试执行器 # 执行测试并输出测试结果
测试用例发现约定:
测试用例方法必须以 test_开头
测试用例类必须以 Test开头
测试文件必须以 test_开头
多个用例根据用例名称顺序执行
命令行运行方式:
# 指定多个测试模块运行
python -m unittest test_module1 test_module2
# 指定测试模块的路径运行
python -m unittest path/test_module.py
# 指定测试类内的测试用例方法运行
python -m unittest test_module.TestClass
# 指定测试模块内的测试类内的测试用例方法运行
python -m unittest test_module.TestClass.test_method
# 参数
-v 更详细的输出结果
-s directory 指定开始搜索的目录
-p pattern 指定文件匹配模式(默认是 test*.py)
-t directory 指定项目的最上层目录(默认是开始时所在的目录)
代码内运行:
import unittest
from utils.HTMLTestRunner import HTMLTestRunner
if __name__ == '__main__':
# suite = unittest.TestSuite()
# 添加单个用例
# suite.addTest(test=TestOneClass("test_001_login"))
# suite.addTest(test=TestOneClass("test_002_register"))
# 添加用例集
# testcases = [TestOneClass("test_001_login"), TestOneClass("test_002_register")]
# suite.addTests(tests=testcases)
# 指定目录查找测试用例集
suite = unittest.defaultTestLoader.discover(start_dir="./testcase", pattern="test_*.py")
# 运行 添加defaultTest 可以指定运行的测试套件。默认运行全部用例。
unittest.main(defaultTest="suite")
# 默认运行全部用例
# unittest.main()
# 使用 HTMLTestRunner 报告运行
with open(os.path.join("report", "testreport.html"), "wb") as f:
HTMLTestRunner(stream=f, title="unittest test report", description="this is description").run(suite)
跳过
import unittest
class DemoOne(unittest.TestCase):
@unittest.skip(reason="直接跳过")
def test_1_02(self):
self.assertEqual(1, 1)
@unittest.skipIf(condition=(1 == 1), reason="条件满足 跳过")
def test_1_03(self):
self.assertEqual(1, 1)
@unittest.skipUnless(condition=(1 == 1), reason="条件满足 不跳过")
def test_1_04(self):
self.assertEqual(1, 10)
@unittest.expectedFailure # 预期失败,如果用例断言失败,不会将结果添加到失败统计中
def test_1_05(self):
ic("@unittest.expectedFailure")
self.assertEqual(1, 2)
@unittest.skip(reason="跳过类")
class DemoTwo(unittest.TestCase):
def test_2_01(self):
self.assertEqual(1, 3)
子测试,测试用例内继续测试
class DemoTwo(unittest.TestCase):
def test_2_01(self):
self.assertEqual(1, 3)
def test_2_02(self):
self.assertEqual(10, 10)
for i in range(5):
with self.subTest(i==i): # 使用子测试,可以在测试用例方法内继续执行测试用例
self.assertEqual(i % 2, 0)
下图为执行结果
unittest.TestCase内的断言方法
Method | Checks that | New in |
---|---|---|
| ||
| ||
| ||
| ||
| 3.1 | |
| 3.1 | |
| 3.1 | |
| 3.1 | |
| 3.1 | |
| 3.1 | |
| 3.2 | |
| 3.2 |
Method | Checks that | New in |
---|---|---|
| ||
| ||
| 3.1 | |
| 3.1 | |
| 3.1 | |
| 3.1 | |
| 3.1 | |
| 3.2 | |
a和b具有相同数量的相同元素,无论它们的顺序如何 | 3.2 |
测试套件添加
suite = unittest.TestSuite()
# 测试套件 方式一:单个添加,顺序执行
# suite.addTest(DemoOne("test_1_01"))
# suite.addTest(DemoThree("test_3_01"))
# suite.addTest(DemoOne("test_1_04"))
# 测试套件 方式二:通过列表管理用例集,顺序执行
# test_cases = [DemoOne("test_1_01"), DemoThree("test_3_01"), DemoOne("test_1_04")]
# suite.addTests(test_cases)
# 测试套件 方式三:通过 模块名.类名 加载用例
suite.addTests(unittest.TestLoader().loadTestsFromNames(names=["demo2.DemoThree", "demo1.DemoOne"]))
# 测试套件 方式三:通过 类名 加载用例
# suite.addTests(unittest.TestLoader().loadTestsFromTestCase(testCaseClass=DemoOne))
# 测试套件 方式三:通过 指定路径加载用例
# discover = unittest.defaultTestLoader.discover(start_dir=current_path, pattern="demo*.py")
运行测试,生成报告
import unittest
# txt报告
with open(current_path + "\\report.txt", "w") as report:
# verbosity=2 输出详细结果 可选:0:不输出;1:简单输出(默认显示 . 的方式);2:详细
runner = unittest.TextTestRunner(stream=report, verbosity=2)
runner.run(test=suite)
runner.run(test=discover)
# 使用html报告 需要将HTMLTestRunner.py复制到Python/lib目录下
from HTMLTestRunner import HTMLTestRunner
with open(current_path + r"\report.html", 'wb') as report:
# verbosity=2 输出详细结果 可选:0:不输出;1:简单输出(默认显示 . 的方式);2:详细
runner = HTMLTestRunner(stream=report, title="测试报告", description="描述", verbosity=2).run(test=suite)
# runner.run(test=discover)
HTMLTestRunner 报告下载地址 ,提取码:pjiz
接口自动化:
+, 接口session使用,关联
import unittest
import warnings
import requests
# 模块级别 在当前模块内最先执行
def setUpModule():
createConnection()
# 模块级别 在当前模块内最后执行
def tearDownModule():
closeConnection()
class TestShop(unittest.TestCase):
@classmethod
def setUpClass(cls): # 类级别 在当前类内最先执行
pass
@classmethod
def tearDownClass(cls): # 类级别 在当前类内最后执行
pass
def setUp(self): # 方法级别 在每个方法前执行
# 初始化实例化session对象
self.session = requests.session()
warnings.filterwarnings("ignore")
def tearDown(self): # 方法级别 在每个方法结束后执行
self.session.close()
def test_code(self):
# 实例化响应结果
response = self.session.get("http://localhost/index.php?m=Home&c=User&a=verify")
try:
# 断言响应码
self.assertEqual(200, response.status_code)
# print("状态码成功")
# 断言响应类型
self.assertIn("image", response.headers.get("Content-Type"))
# print("图片类型成功")
except Exception as e:
print(e)
def test_login(self):
self.test_code()
url_login = "http://localhost/index.php?m=Home&c=User&a=do_login"
data = {"username": "13899999999", "password": "111111", "verify_code": "8888"}
response = self.session.post(url_login, data)
try:
# print(response.json())
self.assertEqual(1, response.json().get("status"))
self.assertIn("登陆成功", response.json().get("msg"))
except Exception as e:
print(e)
def test_order(self):
self.test_login()
url_order = "http://localhost/Home/Order/order_list.html"
response = self.session.get(url_order)
# print(response.text)
try:
self.assertEqual(200, response.status_code)
except Exception as e:
print(e)
1,直连数据库:
"""方法封装"""
import pymysql
class Utils:
#获取链接
@classmethod
def get_con(cls):
con = pymysql.Connect(host="localhost",
user="root",
password="root",
port=3306,
database="books",
charset="utf8")
return con
#获取游标
@classmethod
def get_cursor(cls, con):
cursor = con.cursor()
return cursor
#关闭链接,关闭游标
@classmethod
def close_resource(cls, con, cursor):
if con:
con.close()
con = None
if cursor:
cursor.close()
cursor = None
if __name__ == '__main__':
con = Utils().get_con()
cur = Utils().get_cursor(con)
try:
cur.execute("select title from t_book")
cur.execute("select * from t_book")
print(cur.fetchall())
#事物提交
con.commit()
except Exception as e:
#事物回滚
cur.rollback()
finally:
#关闭链接,关闭游标
Utils().close_resource(con, cur)
2,mock
"""mock模拟接口实现,解除第三方接口依赖,模拟系统异常"""
from unittest import mock
# 前置接口
def login(tel, name):
return False
# 后置接口
def cart():
if login:
print("通过")
class Test:
@classmethod
def test_cart(cls):
# 模拟登陆成功
login = mock.Mock()
if login:
flag = login("123", "1234")
print(flag)
cart()
if __name__ == '__main__':
Test().test_cart()
3,统计数据库查询结果的行数: cursor.rowcount()
获取一行数据:cursor.fetchone()
获取所有行: cursor.fetchall()
获取cookies: response.cookies
获取cookies的某一项的值: response.cookies.get("PHPSESSION")
响应状态码:response.status_code
响应文本:response.text
响应URL:response.url
响应头:response.headers
响应编码集:response.encoding