一.单元测试框架
1.unittest
unittest模块是python自带的测试框架,主要用于单元测试,可以对多个测试用例进行管理和封装,并通过执行用例输出测试结果。 unittest中的几个概念:
- TestCase(测试用例):一个测试用例就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试环境的还原(tearDown)。单元测试中一个测试用例就是一个完整的测试单元。
- TestSuite(测试套件):多个测试用例集合在一起就是一个测试套件,而且测试套件也可以嵌套测试套件。
- TestFixture(测试固件):测试用例中固定的代码,代码中存在相同的部分,对相同的代码进行统一的管理。
- TestRunner(测试运行器):用来执行测试用例的,通过TestRunner中的run()方法来执行TestSuite/TestCase中的run(result)方法。并在执行完成后,将测试结果保存到TestResult实例中。
实例:登录接口
请求
请求方法:post
请求路径:/user/login/
| 参数名 | 类型 | 必填项 | 说明 |
|---|---|---|---|
| account | string | Y | 用户名 |
| password | string | Y | 密码 |
| remember | string | N | 记住密码 |
响应
{
"error": "0",
"errmsg": "登录成功!",
}
1.1 测试固件
简单实现接口测试:
import requests
import unittest
import json
session = requests.session() # 通过session保持会话
class TZlogin(unittest.TestCase):
def setUp(self):
# 测试固件;在setup中解决csrftoken问题
self.url = 'http://192.168.163.128:8000/user/login/'
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
resp = session.get(url=self.url, headers=self.headers)
self.csrftoken = resp.cookies['csrftoken'] # 获取csrftoken
def test_1(self): # 测试用例必须以:test开头
data = {
'account': 'admin',
'password': '123456',
'remember': 'false',
}
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
'X-CSRFToken': self.csrftoken,
}
r = session.post(url=self.url, headers=header, data=data).text
result = json.loads(r)
self.assertEqual(result['errmsg'],'登录成功!','用例_1:用户名与密码正确') # 断言
def test_2(self):
data = {
'account': 'admin',
'password': '12345',
'remember': 'false',
}
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
'X-CSRFToken': self.csrftoken,
}
r = session.post(url=self.url, headers=header, data=data).text
result = json.loads(r)
self.assertIn('用户名或密码错误!',result['errmsg'], '测试用例_2:密码为空') # 断言
def test_3(self):
data = {
'account': 'admins',
'password': '12345',
'remember': 'false',
}
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
'X-CSRFToken': self.csrftoken,
}
r = session.post(url=self.url, headers=header, data=data).text
result = json.loads(r)
self.assertEqual(result['errmsg'], '用户不存在','测试用例_2:用户名错误') # 断言
def tearDown(self):
pass
if __name__ == '__main__':
unittest.main() # 测试运行器;将所有的操作封装在main()方法中,运行全部测试用例。
使用setup()放置代码的公共部分,类似于一个全局变量,供其他函数调用。
1.2 测试套件
完成测试用例的编写后,需要将测试用例组合成测试用例集,也就是测试条件(TestSuite)。
方法一:将测试用例一个一个添加到测试集中
# 此处修建一个.py文件,作为测试用例集
import test_3 # 导入测试用例
import unittest
if __name__ == '__main__':
loginsuite = unittest.TestSuite() # 创建一个测试集合
loginsuite.addTest(test_3.TZlogin('test_1')) # 向测试集中添加测试用例test_1
loginsuite.addTest(test_3.TZlogin('test_2')) # 向测试集中添加测试用例test_2
loginsuite.addTest(test_3.TZlogin('test_3')) # 向测试集中添加测试用例test_2
unittest.TextTestRunner(verbosity=2).run(loginsuite) # 测试运行器
# 注:verbosity参数控制输出的错误报告的详细程度默认是 1;
# 如果设为 0,则不输出每一用例的执行结果;
# 如果设为 2,则输出详细的执行结果;
方法二:将测试用例一次性添加到测试集中
if __name__ == '__main__':
loginsuite = unittest.TestSuite()
loginSuiteTest = [ # 创建一个测试集合
test_3.TZlogin('test_1'), # 测试用例:test_1
test_3.TZlogin('test_2'), # 测试用例:test_2
test_3.TZlogin('test_3') # 测试用例:test_3
]
loginsuite.addTests(loginSuiteTest)
unittest.TextTestRunner().run(loginsuite)
方法三:通过makeSuite方法来创建测试用例类中所有测试用例的测试套件
if __name__ == '__main__':
suite = unittest.makeSuite(test_3.TZlogin, 'test') # 查找所有以test开头的函数
unittest.TextTestRunner().run(suite)
当查找多个测试类时:
if __name__ == '__main__':
suite_1 = unittest.makeSuite(test_3.TZlogin, 'test')
suite_2 = unittest.makeSuite(test_3.GPlogin, 'test')
suite = unittest.TestSuite(suite_1, suite_2)
unittest.TextTestRunner().run(suite)
1.3 测试运行器
方法一:TestRunner() unittest中提供了TestRunner类,为测试的运行提供了环境,最常用的就是TestRunner类,整个类使用了文字化的运行方式来报告最后的测试结果。
if __name__ == '__main__':
runner = unittest.TextTestRunner() # 使用TxstTestRunner类构造一个运行器对象。此对象提供了run方法
runner.run(suite()) # suite():测试套件实例
方法二:unittest.main() 使用unittest的main方法,在全局直接加载所有测试类中的测试用例,并全部执行。
if __name__ == '__main__':
unittest.main()
方法三:批量执行测试用例文件
if __name__ == '__main__':
path = '.' # 定义测试用例.py存储的路径
dc = unittest.defaultTestLoader.discover(path,pattern='test*.py') # pattern:识别目录下所有以test开头的.py文件
unittest.TextTestRunner().run(dc)
1.4 测试报告
在批量执行完测试用例后,生成的测试结果是文本形式的,不够直观,为了更好的展示测试报告,最好是生成HTML格式的。unittest里面是不能生成html格式报告的,需要导入一个第三方的模块:HTMLTestRunner。
HTMLTestRunner模块不能通过pip导入安装,需要自己手动下载。
下载地址:tungwaiyip.info/software/HT…
下载完成后,将HTMLTestRunner.py放入python目录下的Lib中。因为HTMLTestRunner.py文件是python2写的,使用python3时需要修改以下几处地方:
- 第一处:第94行,将import StringIO修改为import io
- 第二处:第539行,将stringIO().StringIO()修改为io.StringIO()
- 第三处:第631行,将print >>sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)修改为print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
- 第四处:第642行,将if not rmap.has_key(cls):修改为if not cls in rmap:
- 第五处:第766行,将uo = o.decode('latin-1')修改为uo = e
- 第六处:第772行,将ue = e.decode('latin-1')修改为ue = e
- 第七处:第778行,将output = saxutils.escape(uo+ue)修改为output = saxutils.escape(str(uo)+str(ue)) 执行测试时,加入测试报告
import unittest
import HTMLTestRunner
from API import test_3
def suite():
logintest = unittest.TestSuite()
logintest.addTest(test_3.TZlogin('test_1'))
logintest.addTest(test_3.TZlogin('test_1'))
logintest.addTest(test_3.TZlogin('test_1'))
logintest.addTest(test_3.GPlogin('test_1'))
return logintest
if __name__ == '__main__':
file_path = "F:\\projects\\untitled\\result.html" # 测试报告存储路径
fp = open(file_path, 'wb')
runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='测试报告', description='详情')
unittest.TextTestRunner()
runner.run(suite())
1.5 使用smtplib发送测试报告
- 使用smtplib发送一份邮件
import smtplib
from email.mime.text import MIMEText
# 准备邮件相关参数
smtpserver = 'smtp.**.com' # 邮箱服务器
sender = '****@***.com' # 发件人
pwd = '***' # 客户端登录授权码
receiver = '****@**.com' # 收件人
# 写邮件
subject = '163邮箱内容' # 使用163邮箱时,邮件标题有敏感字母限制
body = '<html><h1>邮件内容</h1></html>' # 邮件内容最好加入html标签,否则容易识别为垃圾邮件
msg = MIMEText(body,'html','utf-8')
msg['From'] = sender
msg['TO'] = receiver
msg['Subject'] = subject
# 发送邮件
try:
smtp = smtplib.SMTP() # 163邮箱
except:
smtp = smtplib.SMTP_SSL(smtpserver, 465) # QQ邮箱需要SSL认证
smtp.connect(smtpserver)
smtp.login(sender, pwd)
smtp.sendmail(sender,receiver,msg.as_string())
smtp.quit()
1.6 装饰器的使用
2.pytest
安装:pip install -U pytest
检查安装的版本:pytest --version
编写pytest测试用例需要遵守的规则:
- 测试文件以test_开头(或以_test结尾)
- 测试类以Test开头,并且不能带有__init__方法
- 测试函数以test_开头
- 断言使用基本的assert就可以。