概念
对功能/代码的最小单元进行测试--函数或者类的方法
被测函数/功能/方法
def add(a,b):
return a + b
编写测试用例
#a = 1, b = 1 ,expected = 2
#得到实际结果
actual = add(a = 1, b = 1)
执行用例,把用例传入被测函数,然后调用被测函数,然后进行判断
def demo_add(num1,num2,expected:sum):
#执行测试用例
actual = add(num1,num2)
# if actual == expected:
# print("测试用例通过")
# else:
# print("测试用例失败")
#断言
assert actual == expected
result = demo_add(1,1,2)
print(result)
在用python进行测试中,用assert 而不用if
当使用assert断言,如果通过,程序正常执行,如果不通过,抛出异常类型AssertError
在没有用单元测试框架之前,也可以做自动化测试
- 编写测试用例函数,手工调用被测函数
- 如果用例失败,要手工添加try...except捕获异常,免得程序中断
- 要收集很多用例,放到一个统一的模块
- 还要手写测试报告
单元测试框架
框架:提供工具的集合,一套解决方案
Unittest
Python 内置的单元测试框架
- 提供了工具的集合,使用起来便利
- 一个框架意味着要遵守框架规则
作用:
-收集用例
-处理断言
-测试报告
概念:
-test case: 测试用例
-test suite: 测试套件/测试用例集合
-test loader: 测试加载
-test runner: 运行器,执行器
-fixture: 夹具,前置准备和后置清理
-test case: 测试用例
测试过程:
1.导入unettest框架里的TestCase类
from unittest import TestCase
2.编写被测试函数,功能
#被测试函数,登录功能
def login(username = None,password = None):
if username is None or password is None:
return {"code":'400','msg':"用户名或密码为空"}
if username == "conlin" and password == '123':
return {'code':'200','msg':'登录成功'}
return {'code':'300','msg':'用户名或密码错误'}
3.建立测试类,必须继承unittest.TestCase,编写测试用例函数,类名和方法名必须以test开头
from unittest import TestCase
from homework.homework0927.login import login
class TestLogin(TestCase):
def test_login_1(self):
username = "yuz"
password = "123"
expected = {'code':'200','msg':'登录成功'}
actual = login(username,password)
self.assertEqual(expected,actual)
def test_login_2(self):
username = None
password = '123'
expected = {"code":'400','msg':"用户名或密码为空"}
actual = login(username,password)
self.assertEqual(expected,actual)
def test_login_3(self):
username = "conlin"
password = "123"
expected = {'code':'200','msg':'登录成功'}
actual = login(username,password)
self.assertEqual(expected,actual)
4.把测试用例填入方法,按执行用例,不用调用方法,框架会自动调用,还会把类里全部的用例方法都执行
运行成功
测试用例运行失败
点击错误链接能告诉你哪一条用例失败
也可以用unittest的内置方法assertEqual()
self.assertEqual(expected,actual)
断言
在用python进行测试中,用断言而不用if
常用断言:
assertEqual(expected,actual)断言是否相等
assertTrue()断言是否为True,万能
assertIn()断言是否在成员里
当使用assert断言,如果通过,程序正常执行,如果不通过,抛出异常类型AssertError
能够告诉你详细错误信息,并且判断应该得到的正确的信息
-test loader: 测试加载
加载测试用例
#在test_case_file文件夹存放用例
suite = unittest.defaultTestLoader.discover("test")
或者
要传入的参数是测试用例的文件夹名称,里面的py文件要以test开头
新建的时候选择包(package),有__init__.py文件,所有测试用例的py文件都要放在包里
存放测试用例文件夹路径
测试用例文件夹存放路径:要放在项目根目录下创建的包(package),不能放在运行文件.py所在的项目根目录下
-test runner: 运行器,执行器
运行用例
要传入的参数是上面收集到的测试用例集合,是在TestLoader类里创建的实例,这个实例调用了dicover方法
查看结果
·代表通过.F代表失败
生成测试报告
先收集测试用例集合,然后用unittestreport插件生成报告
在unittestreport这个插件里TestRunner这个类里面创建一个实例,并且要输入参数,参数最少也要输入从TestLoader类里创建的实例,也就是测试用例合集
还能在参数里传入要定制的内容
实例调用run方法后得到测试报告
-fixture: 夹具,前置准备和后置清理
setUp(self)--前置条件 tearDown(self)--后置动作
每次执行一个用例前,执行前置条件,执行用例,执行后置动作.再开始第二个用例的前置条件...
import unittest
class TestAdd(unittest.TestCase):
# 要连接数据库作为前置条件
def setUp(self) -> None:
print("连接数据库....")
# 断开数据库连接为后置动作
def tearDown(self) -> None:
print("断开数据库连接...")
def test_db(self):
# 测试数据库
print("正在执行测试")
self.assertTrue(1 + 1 == 2)
def test_db2(self):
print("正在执行测试2")
self.assertEqual(1, 1)
类的前置条件和后置动作(要先定义类方法@classmethod)
setUpClass(cls)--前置条件 tearDownClass(cls)--后置条件
一个类只执行一次
import unittest
class TestAdd(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_db(self):
# 测试数据库
print("正在执行测试")
self.assertTrue(1 + 1 == 2)
def test_db2(self):
print("正在执行测试2")
self.assertEqual(1, 1)
前置条件和后置动作里的方法,不能用动态输入input,比如作为测试用例中,要输入的用户名和密码
1.因为在前置条件里输入的数据,并不是实例化的过程,不能作为实例属性被用例调用 ,
只能在测试用例里调用setUp()方法,这样就会重复2次输入数据
2.也不能在测试用例里用动态输入,这样只能在调试时候能用到
批量执行(run.py)的时候不能手动输入,导致测试报告没有数据
3.TestCase里的测试用例的数据,都要是现成的数据,不能使用input传入
需要手工把要输入的数据填入excel,再读取excel提取数据到测试用例