单元测试就是对单个模块或者是单个类或者是单个函数进行测试;一般是开发做的,按照测试阶段来分,一般是单元测试、集成测试、系统测试、验收测试。
2.为什么需要做单元测试?
1)单元测试之后,才是集成测试。单个单个功能模块测试通过之后,才能将单个功能模块集成起来做集成测试。为了从底层发现bug,减少模块合成之后出现的问题。
2)越早发现bug越好,这样可以早点发现问题,不然等问题积累到后面,如果做错了就要推倒重来,对于时间和经费来说,也是非常的浪费。
对于我们测试来说:我们就单元测试是为了执行测试用例的。
1.unittset框架最核心的四个概念:
- TestSuite:多个测试用例集合在一起。TestLoader:是用来把TestCase加载到TestSuite中的。
- TextTestRunner:用来执行测试用例的。
- fixture:测试用例环境的搭建和销毁,测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。
2.单元测试案例
def login_chek(username,password):
"""
登录校验的函数
:param username:账号
:param password:密码
:return:
"""
if 6 <= len(password) <= 18:
if username == 'python18' and password == 123456:
return {'code':'0000','massage':'账户密码正确,登陆成功'}
else:
return {'code':'0001','massage':'账户或者密码不正确,登陆失败'}
else:
return {'code': '0001', 'massage': '密码长度必须在6-18位之间'}
-
设计用例测试上面的登陆校验是否正常?
1.TestCase类编写测试用例
继承unittest里面的TestCase类,继承这个类,写能写测试用例,每个测试用例我们都要记得引入fixture,做一些准备以及结束的工作。
编写测试用例步骤如下:
1)导入unittest模块、被测文件或者其中的类(import unittest)
2)创建一个测试类,并继承unittest.TestCase
3)重写setUp和tearDown方法(如果有初始化条件和结束条件)
4)定义测试函数、函数名以test开头。测试用例
import unittest
from pack import login_check
# 继承unittest的TestCase类
class LoginTest(unittest.TestCase):
def setUp(self):
print("执行每一条测试用例之前都会执行这个方法,可以使用该方法,做测试之前的环境准备工作")
def tearDown(self):
print("执行完每一条测试用例之后都会执行该方法,可以使用该方法来恢复环境")
# 一个测试用例就是该类中的一个方法。测试用例的方法必须要以test开头
# 正常的测试用例(账号、密码正确,登录成功)
def test_login(self):
# 预期结果
excepted = {'code':'0000','massage':'账户密码正确,登陆成功'}
# 传入参数
data = ('python18','123456')
# 调用被测函数,传入参数(需要解包),获取实际结果
res = login_check(*data)
try:
self.assertEqual(excepted,res) # 通过实例对象(self)来调用assertEqual()方法
except AssertionError as e:
print("该测试用例测试未通过") # 可通过异常捕获来获取
raise e # 此处需要使用raise主动抛出异常
else:
print("该测试用例测试通过")
# 异常用例(账户错误,密码正确)
def test_username_error(self):
excepted = {'code':'0001','massage':'账户或者密码不正确,登陆失败'}
data = ('java','123456')
res = login_check(*data)
try:
self.assertEqual(excepted,res)
except AssertionError as e:
print("该测试用例测试未通过") # 可通过异常捕获来获取
raise e # 此处需要使用raise主动抛出异常
else:
print("该测试用例测试通过")
# 异常用例(账户正确,密码在6-18位,密码错误)
def test_password_error(self):
excepted = {'code':'0001','massage':'账户或者密码不正确,登陆失败'}
data = ('python','112233')
res = login_check(*data)
try:
self.assertEqual(excepted,res)
except AssertionError as e:
print("该条测试用例测试未通过")
raise e
else:
print("该条测试用例测试通过")
# 异常用例(账户正确,密码少于6位)
def test_password_lt6(self):
excepted = {'code': '0001', 'massage': '密码长度必须在6-18位之间'}
data = ('python','1238777')
res = login_check(*data)
try:
self.assertEqual(excepted,res)
except AssertionError as e:
print("该条测试用例测试未通过")
raise e
else:
print("该条测试用例测试通过")
# 异常用例(账户正确,密码长度大于18位)
def test_password_gt18(self):
excepted = {'code': '0001', 'massage': '密码长度必须在6-18位之间'}
data = ('python','12333444455534343441675')
res = login_check(*data)
try:
self.assertEqual(excepted,res)
except AssertionError as e:
print("该条测试用例测试未通过")
raise e
else:
print("该条测试用例测试通过")
1.TestSuite&TestLoader的使用
TestSuite:测试集,把所有测试用例都存进来。常用的方法如下:
unittest.TestSuite()
方法一:addTest() 添加一个测试用例
方法二:addTest([,,,,]) 添加多个测试用例 添加用例的方式都是一样的。
unittest.TsetLoader()
方法三:unittest.TestLoader.loadTestFromModule(模块名)不需要加引号(注意要导入模块)
方法四:unittest.TestLoaderTestsFromTestCase(测试类名)不需要加引号
2.总结和疑问
1.定义的测试类和测试套件写在不同的模块里,为什么?
2.为何引入测试集,方便批量进行单元测试。
import unittest
from pack.python13 import LoginTest
from pack import python13
# 创建一个测试集合
suite = unittest.TestSuite()
# 添加测试用例
# 第一种 单个用例添加:接收的参数是测试用例的对象
suite.addTest(LoginTest('test_login'))
suite.addTest(LoginTest('test_username_error'))
suite.addTest(LoginTest('test_password_lt6'))
# 第二种 一次添加多条测试用例
suite.addTests([LoginTest('test_login'),LoginTest('test_username_error'),LoginTest('test_password_lt6')])
# 第三种 一次添加一个测试用例类(类名不需要加引号)
loader = unittest.TestLoader()
suite.addTest(loader.loadTestsFromTestCase(LoginTest)) # 需要先将LoginTest类导进来
# 第四种 通过模块去添加
loader = unittest.TestLoader()
suite.addTest(loader.loadTestsFromModule(python13))
# 运行测试集合
# 创建一个runner对象
runner = unittest.TextTestRunner()
runner.run(suite) # 执行测试套件
检查 | |
---|---|
assertEqual(a,b) | a == b (判断两个值是否相等) |
assertNotEqual(a,b) | a != b (判断两个值是否不相等) |
assertTrue(x) | bool(x) is True (判断对象的布尔值x是否为True) |
assertFalse(x) | bool(x) is False (判断对象的布尔值x是否为False) |
assertIs(a,b) | a is b(判断a和b是否是同一对象) |
assertIsNot(a,b) | a is not b |
assertIn(a,b) | a in b |
assertNotIn(a,b) |
需要将 HTMLTestRunnerNew 测试报告模板文件复制至site-packages目录下。
1.TextTestRunner的用法
-
测试用例已经集合完毕,如何来执行测试用例?
需要用到TextTestRunner,执行测试集合,用到的是TextTestRunner(),用run方法。
#创建runner对象
runner = unittest.TextTestRunner()
#这里将传入测试集合进行执行
runner.run(suite)
- . 代表测试用例通过 一个点代表一个测试用例
- E 代表测试用例执行出错了
3.生成测试报告
# 新建一个register_report.py文件
import unittest
from python.register_testcase import RegisterTest
from HTMLTestRunnerNew import HTMLTestRunner
# 创建一个测试集合
suite = unittest.TestSuite()
# 将测试用例加载到测试集合
loader = unittest.TestLoader()
suite.addTest(loader.loadTestsFromTestCase(RegisterTest))
# 1、执行测试(套件)集合,并生成文本格式的测试报告
with open("report.txt","wb",encoding='utf-8') as f: # 报告内容过于鸡肋,几乎不用
runner = unittest.TextTestRunner(f)
runner.run(suite)
# 2、执行测试(套件)集合,并生成HTML格式的测试报告
with open('report.html','w') as f:
runner = HTMLTestRunner(stream=f, # 需要写入的文件名
verbosity=2, # 写入的等级,2是最高级的,也是最详细的
title ='python_test_rerport', # 报告的名称
description='这是pytest单元测试的一份测试报告', # 报告的相关描述
tester='WL') # 测试者姓名
runner.run(suite)