接口测试笔记

341 阅读6分钟

一.单元测试框架

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就可以。