1.unittest的基本内容
1.1unittest
unittest
是 Python 标准库中的一个单元测试框架,它允许你编写测试用例来测试你的代码。通过编写测试用例,你可以确保你的代码按照预期工作,并在将来进行修改时保持其功能不变。TestCase一个测试用例是一个具体的测试单元,它包含了执行单个测试所需的代码和断言。
TestSuite测试套件是一个包含多个测试用例或测试套件的集合。
TestRunner测试运行器用于执行测试套件或测试用例,并收集测试结果
Test Fixtures测试固件指的是在测试之前进行准备(如设置测试环境)和在测试之后进行清理(如还原测试环境)的代码。
建立test1.py与test2.py文件
import unittest
class Test1(unittest.TestCase):
def test_method1(self):
print('1-1....')
def test_method2(self):
print('1-2....')
import unittest
from test1 import Test1
from test2 import Test2
# 实例化套件对象
suite = unittest.TestSuite()
# 方法1
# suite.addTest(Test1('test_method1'))
# suite.addTest(Test1('test_method2'))
# suite.addTest(Test2('test_method1'))
# suite.addTest(Test2('test_method2'))
# 方法2
# unittest.makeSuite(Test1)将Test1类中的所有方法调用
suite.addTest(unittest.makeSuite(Test1))
suite.addTest(unittest.makeSuite(Test2))
# 实例化运行对象
runner = unittest.TextTestRunner()
runner.run(suite)
2.unittest的基本运用
第一步:先制作一个tools.py文件
# 模组名称为tools.py
def add(a, b):
return a + b
# print('tools:', __name__)
def login(username, password):
if username == 'admin' and password == '123456':
return '登录成功'
else:
return '登录失败'
第二步:创建一个teatadd.py文件,在文件中引入tools.py文件中的add方法
import unittest
from tools import add
class AddTest(unittest.TestCase):
def test_add1(self):
if add(1, 2) == 3:
print('success...1')
def test_add2(self):
if add(10, 20) == 30:
print('success...2')
第三步:调用teatadd.py文件,使用makeSuite()方法调用AddTest类中所用的方法
import unittest
from testadd import AddTest
# 实例化套件对象
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(AddTest))
# 实例化运行对象
runner = unittest.TextTestRunner()
runner.run(suite)
最终结果如下:
分析:
在tools.py文件中创建了一个add的运算方法,实现两个参数的相加,在teatadd.py文件中引用并提供了相应的参数,当运行正常时即可通过主文件输出
3.输入登录的测试用例
3.1基础运用
这次调用的是tools.py文件中的login登录判断文件,当用户名与密码正确时输出“登录成功”,反之则输出“登录失败”
下面的代码则是判断tools.py文件的返回值是登录成功还是登录失败
import unittest
from tools import login
class TestLogin(unittest.TestCase):
def test_username_password_ok(self):
"""输入测试用例"""
if login('admin', '123456') == '登录成功':
print('pass')
else:
print('fail')
def test_username_err(self):
if login('root', '123456') == '登录失败':
print('pass')
else:
print('fail')
def test_password_err(self):
if login('admin', '123123') == '登录失败':
print('pass')
else:
print('fail')
def test_username_password_err(self):
if login('root', '123123') == '登录失败':
print('pass')
else:
print('fail')
运行结果如下:
3.2多个文件的使用
将多个文件放入指定目录中(这里是teat)
使用以下方式调用:
import unittest
# 实例化加载对象
suite = unittest.TestLoader().discover('./test', 'test*')
# runner = unittest.TextTestRunner()
# runner.run(suite)
runner = unittest.TextTestRunner().run(suite)
结果如下:
4.Fixture的使用
4.1fixture的内容
以下是常用的几个方法
# 方法执行之前会执行
def setup(self):
pass
# 方法执行之后会执行
def tearDown(self):
pass
# 类中所有方法执行之前会执行
@classmethod
def setupClass(cls):
pass
# 类中所有方法执行之后会执行
@classmethod
def tearDownClass(cls):
pass
# 代码文件之前
def setupModule():
pass
4.2案例运用
# 输出后发现setUpClass与tearDownClass的输出结果连在一起了
# 其实这个输出要将其重定向到文件而不是控制台。
import unittest
from tools import login
class TestLogin(unittest.TestCase):
def setUp(self):
print('输入网址...')
def tearDown(self):
print('关闭当前网页...')
@classmethod
def setUpClass(cls) -> None:
print('----打开浏览器...')
@classmethod
def tearDownClass(cls) -> None:
print('----关闭浏览器...')
def test_1(self):
if login('admin', '123456') == '登录成功':
print('pass')
else:
print('err')
def test_2(self):
if login('root', '123456') == '登录失败':
print('pass')
else:
print('err')
输出结果为:
4.3解决setUpClass(cls)与tearDownClass(cls)的结果在同一行的问题
import unittest
from tools import login
class TestLogin(unittest.TestCase):
def setUp(self):
# print('输入网址...')
with open('a.txt', 'a', encoding='utf-8') as f:
f.write("输入网址\n")
def tearDown(self):
# print('关闭当前网页...')
with open('a.txt', 'a', encoding='utf-8') as f:
f.write("关闭当前网页\n")
@classmethod
def setUpClass(cls) -> None:
# print('----打开浏览器...')
with open('a.txt', 'a', encoding='utf-8') as f:
f.write("打开浏览器\n")
@classmethod
def tearDownClass(cls) -> None:
# print('----关闭浏览器...')
with open('a.txt', 'a', encoding='utf-8') as f:
f.write("关闭浏览器\n")
def test_1(self):
if login('admin', '123456') == '登录成功':
# print('pass')
with open('a.txt', 'a', encoding='utf-8') as f:
f.write("测试方法1\n")
else:
print('err')
def test_2(self):
if login('root', '123456') == '登录失败':
# print('pass')
with open('a.txt', 'a', encoding='utf-8') as f:
f.write("测试方法2\n")
else:
print('err')
输出结果:
5.断言
5.1案例
# 断言
# assertEqual与assertIn
import unittest
from tools import login
class TestLogin(unittest.TestCase):
def test_username_password_ok(self):
"""输入测试用例"""
self.assertEqual('登录成功', login('admin', '123456'))
def test_username_err(self):
self.assertEqual('登录失败', login('root', '123456'))
# self.assertEqual('登录成功', login('root', '123456'))
def test_password_err(self):
self.assertEqual('登录失败', login('admin', '123123'))
def test_username_password_err(self):
self.assertEqual('登录失败', login('root', '123123'))
# self.assertIn('失败', login('root', '123123'))
运行结果:
5.2案例改进
# unittest默认是不支持参数测试数据
# 这里需要在终端输入pip install parameterized
import unittest
from parameterized import parameterized
from tools import login
# 格式为[[]]或[()]
data = [
('登录成功', 'admin', '123456'),
('登录失败', 'root', '123456'),
('登录失败', 'admin', '123123'),
('登录失败', 'root', '123123')
]
# 定义测试类
class TestLogin(unittest.TestCase):
# 使用变量来代替
@parameterized.expand(data)
def test_login(self, expect, username, password):
self.assertEqual(expect, login(username, password))
导出后如下:
5.3案例再次改进
再上述案例中,测试用例是放在测试类文件里面,这样不实用不方便,为此,创建了一个储存测试用例的JSON文件,然后让测试类获取文件中的数据即可,下面是JSON文件中的数据和测试类代码
JSON数据如下,文件名为:data.json
[
{
"username": "admin",
"password": "123456",
"expect": "登录成功"
},
{
"username": "root",
"password": "123123",
"expect": "登录失败"
}
]
import unittest
from parameterized import parameterized
from tools import login
# 组织数据
def achieve_data():
with open("data.json", encoding="utf-8") as f:
result = json.load(f)
data = []
for i in result:
data.append((i.get('expect'), i.get('username'), i.get('password')))
return data
class TestLogin(unittest.TestCase):
# 使用变量来代替
@parameterized.expand(achieve_data())
def test_login(self, expect, username, password):
self.assertEqual(expect, login(username, password))