接口测试 接口自动化测试,完整入门篇

lovesoo · 发布于 2017年12月01日 · 最后由 lovesoo 回复于 2017年12月14日 · 4552 次阅读
本帖已被设为精华帖!

1. 什么是接口测试

顾名思义,接口测试是对系统或组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。其中接口协议分为HTTP,WebService,Dubbo,Thrift,Socket等类型,测试类型又主要分为功能测试,性能测试,稳定性测试,安全性测试等。
在分层测试的“金字塔”模型中,接口测试属于第二层服务集成测试范畴。相比UI层(主要是WEB或APP)自动化测试而言,接口自动化测试收益更大,且容易实现,维护成本低,有着更高的投入产出比,是每个公司开展自动化测试的首选。

下面我们以一个HTTP接口为例,完整的介绍接口自动化测试流程:从需求分析到用例设计,从脚本编写、测试执行到结果分析,并提供完整的用例设计及测试脚本。

2. 基本流程

基本的接口功能自动化测试流程如下:
需求分析 -> 用例设计 -> 脚本开发 -> 测试执行 -> 结果分析

2.1 示例接口

接口名称:豆瓣电影搜索
接口文档地址:https://developers.douban.com/wiki/?title=movie_v2#search
接口调用示例:
1) 按演职人员搜索:https://api.douban.com/v2/movie/search?q=张艺谋
2) 按片名搜索:https://api.douban.com/v2/movie/search?q=大话西游
3) 按类型搜索:https://api.douban.com/v2/movie/search?tag=喜剧

3. 需求分析

需求分析是参考需求、设计等文档,在了解需求的基础上还需清楚内部的实现逻辑,并且可以在这一阶段提出需求、设计存在的不合理或遗漏之处。
如:豆瓣电影搜索接口,我理解的需求即是支持对片名,演职人员及标签的搜索,并分页返回搜索结果。

4. 用例设计

用例设计是在理解接口测试需求的基础上,使用MindManager或XMind等思维导图软件编写测试用例设计,主要内容包括参数校验,功能校验、业务场景校验、安全性及性能校验等,常用的用例设计方法有等价类划分法,边界值分析法,场景分析法,因果图,正交表等。
针对豆瓣电影搜索接口功能测试部分,我们主要从参数校验,功能校验,业务场景校验三方面,设计测试用例如下:

5. 脚本开发

依据上面编写的测试用例设计,我们使用python+nosetests框架编写了相关自动化测试脚本。可以完整实现接口自动化测试、自动执行及邮件发送测试报告功能。

5.1 相关lib安装

必要的lib库如下,使用pip命令安装即可:

pip install nose
pip install nose-htmloutput
pip install requests

5.2 接口调用

使用requests库,我们可以很方便的编写上述接口调用方法(如搜索q=刘德华,示例代码如下):

#coding=utf-8
import requests
import json

url = 'https://api.douban.com/v2/movie/search'
params=dict(q=u'刘德华')
r = requests.get(url, params=params)
print 'Search Params:\n', json.dumps(params, ensure_ascii=False)
print 'Search Response:\n', json.dumps(r.json(), ensure_ascii=False, indent=4)

在实际编写自动化测试脚本时,我们需要进行一些封装。如下代码中我们对豆瓣电影搜索接口进行了封装,test_q方法只需使用nosetests提供的yield方法即可很方便的循环执行列表qs中每一个测试集:

class test_doubanSearch(object):

    @staticmethod
    def search(params, expectNum=None):
        url = 'https://api.douban.com/v2/movie/search'
        r = requests.get(url, params=params)
        print 'Search Params:\n', json.dumps(params, ensure_ascii=False)
        print 'Search Response:\n', json.dumps(r.json(), ensure_ascii=False, indent=4)

    def test_q(self):
        # 校验搜索条件 q
        qs = [u'白夜追凶', u'大话西游', u'周星驰', u'张艺谋', u'周星驰,吴孟达', u'张艺谋,巩俐', u'周星驰,大话西游', u'白夜追凶,潘粤明']
        for q in qs:
            params = dict(q=q)
            f = partial(test_doubanSearch.search, params)
            f.description = json.dumps(params, ensure_ascii=False).encode('utf-8')
            yield (f,)

我们按照测试用例设计,依次编写每个功能的自动化测试脚本即可。

5.3 结果校验

在手工测试接口的时候,我们需要通过接口返回的结果判断本次测试是否通过,自动化测试也是如此。
对于本次的接口,我们搜索“q=刘德华”,我们需要判断返回的结果中是否含有“演职人员刘德华或片名刘德华”,搜索“tag=喜剧”时,需要判断返回的结果中电影类型是否为“喜剧”,结果分页时需要校验返回的结果数是否正确等。完整结果校验代码如下:

class check_response():
    @staticmethod
    def check_result(response, params, expectNum=None):
        # 由于搜索结果存在模糊匹配的情况,这里简单处理只校验第一个返回结果的正确性
        if expectNum is not None:
            # 期望结果数目不为None时,只判断返回结果数目
            eq_(expectNum, len(response['subjects']), '{0}!={1}'.format(expectNum, len(response['subjects'])))
        else:
            if not response['subjects']:
                # 结果为空,直接返回失败
                assert False
            else:
                # 结果不为空,校验第一个结果
                subject = response['subjects'][0]
                # 先校验搜索条件tag
                if params.get('tag'):
                    for word in params['tag'].split(','):
                        genres = subject['genres']
                        ok_(word in genres, 'Check {0} failed!'.format(word.encode('utf-8')))

                # 再校验搜索条件q
                elif params.get('q'):
                    # 依次判断片名,导演或演员中是否含有搜索词,任意一个含有则返回成功
                    for word in params['q'].split(','):
                        title = [subject['title']]
                        casts = [i['name'] for i in subject['casts']]
                        directors = [i['name'] for i in subject['directors']]
                        total = title + casts + directors
                        ok_(any(word.lower() in i.lower() for i in total),
                            'Check {0} failed!'.format(word.encode('utf-8')))

    @staticmethod
    def check_pageSize(response):
        # 判断分页结果数目是否正确
        count = response.get('count')
        start = response.get('start')
        total = response.get('total')
        diff = total - start

        if diff >= count:
            expectPageSize = count
        elif count > diff > 0:
            expectPageSize = diff
        else:
            expectPageSize = 0

        eq_(expectPageSize, len(response['subjects']), '{0}!={1}'.format(expectPageSize, len(response['subjects'])))

5.4 执行测试

对于上述测试脚本,我们使用nosetests命令可以方便的运行自动化测试,并使用插件生成html格式测试报告。
运行命令如下:
nosetests -v test_doubanSearch.py:test_doubanSearch --with-html --html-file=TestReport.html

5.5 发送邮件报告

测试完成之后,我们可以使用smtplib模块提供的方法发送html格式测试报告。基本流程是读取测试报告 -> 添加邮件内容及附件 -> 连接邮件服务器 -> 发送邮件 -> 退出,示例代码如下:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def send_mail():
    # 读取测试报告内容
    with open(report_file, 'r') as f:
        content = f.read().decode('utf-8')

    msg = MIMEMultipart('mixed')
    # 添加邮件内容
    msg_html = MIMEText(content, 'html', 'utf-8')
    msg.attach(msg_html)

    # 添加附件
    msg_attachment = MIMEText(content, 'html', 'utf-8')
    msg_attachment["Content-Disposition"] = 'attachment; filename="{0}"'.format(report_file)
    msg.attach(msg_attachment)

    msg['Subject'] = mail_subjet
    msg['From'] = mail_user
    msg['To'] = ';'.join(mail_to)
    try:
        # 连接邮件服务器
        s = smtplib.SMTP(mail_host, 25)
        # 登陆
        s.login(mail_user, mail_pwd)
        # 发送邮件
        s.sendmail(mail_user, mail_to, msg.as_string())
        # 退出
        s.quit()
    except Exception as e:
        print "Exceptioin ", e

6. 结果分析

打开nosetests运行完成后生成的测试报告,可以看出本次测试共执行了51条测试用例,50条成功,1条失败。

失败的用例可以看到传入的参数是:{"count": -10, "tag": "喜剧"},此时返回的结果数与我们的期望结果不一致(count为负数时,期望结果是接口报错或使用默认值20,但实际返回的结果数目是189。赶紧去给豆瓣提bug啦- -)

7. 完整脚本

豆瓣电影搜索接口的完整自动化测试脚本,我已上传到的GitHub。下载地址:https://github.com/lovesoo/test_demo/tree/master/test_douban

下载完成之后,在当前脚本目录下,使用如下命令即可进行完整的接口自动化测试并使用邮件发送最终测试报告(执行命令之前,别忘了修改脚本中邮件发件人及收件人信息为你自己的实际信息):
python test_doubanSearch.py

最终发送测试报告邮件,截图如下:

8. 参考资料

1) requests: http://cn.python-requests.org/zh_CN/latest/
2) nosetests: http://nose.readthedocs.io/en/latest/testing.html
3) nose-html-reporting: https://pypi.python.org/pypi/nose-html-reporting

9. Python 3版本

本文是基于Python 2.7编写,因为有的小伙伴使用的Python 3。特地修改了一个Python3的版本:https://github.com/lovesoo/test_demo/blob/master/test_douban/test_doubanSearch_py3.py

获取更多信息,欢迎加入测试开发交流群:25452556

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 39 条回复
F4d2c5
lovesoo · #1 · 2017年12月04日 作者
D99fd3Donly 回复

修改了一个Python3的版本,代码上传到了GitHub:https://github.com/lovesoo/test_demo/blob/master/test_douban/test_doubanSearch_py3.py

由于原有插件nose-html-reporting不兼容Python3,使用了新的插件nose-htmloutput (https://pypi.python.org/pypi/nose-htmloutput),可以使用如下命令安装:
pip install nose-htmloutput

直接在脚本目录下,使用如下命令运行即可(当然执行测试之前,别忘了修改脚本中邮件发件人及收件人信息为你自己的实际信息):
python test_doubanSearch_py3.py

最终执行结果如下:

有问题的话,欢迎再提问~

12235

这样写用例,如果后续接口变动会不会维护很麻烦

F03979

学习了!

F4d2c5
lovesoo · #3 · 2017年12月01日 作者
122359688e 回复

不会啊,其实可以借鉴WEB自动化测试中page-object模式,我们设计接口自动化测试的时候可以对接口的调用做封装,如果接口变动了,比如增加了一些参数,只需维护封装好的调用方法就行了。

104 seveniruby 将本帖设为了精华贴 12月01日 23:51
104

不错的入门文章,连夜进行加精。

3165

学习了!!

11901

学习了!!

F4d2c5
lovesoo · #8 · 2017年12月04日 作者
104seveniruby 回复

感谢版主😀

F4d2c5
lovesoo · #9 · 2017年12月04日 作者
3165thanksdanny 回复

一起学习~😀

F4d2c5
lovesoo · #10 · 2017年12月04日 作者
11901caolanmiao 回复

💪

2113

不错的实践

56a966

学习了!!,写的蛮详细

D99fd3

执行的时候提示没有--with-html这个选项?为嘛呢?
直接运行脚本的话,也没有任何报告输出,似乎都没有执行测试。。。
这边环境是python3的

F4d2c5
lovesoo · #14 · 2017年12月04日 作者
D99fd3Donly 回复

pip install nose
pip install nose-html-reporting
pip install requests
这些lib安装了吗,代码必须要通过nosetests来运行的~

D99fd3

看了下nosetests -help,真的没有--with-html和--html-report这两个选项。。。。。

D99fd3
F4d2c5lovesoo 回复

肯定是都有安装的啦
刚刚试过把--with-html和--html-report改成了--with-xunit --xunit-file,可以运行了,但是一堆报错啊。。。难道说,nosetests不支持py3吗??
基本都是这样的错

nosetests -h的部分选项

D99fd3


这是安装后的包

F4d2c5
lovesoo · #18 · 2017年12月04日 作者
D99fd3Donly 回复

我安装下Python 3看看 ,这个demo用的是Python 2.7~

D99fd3
F4d2c5lovesoo 回复

我把所有的encode('utf-8')都注释掉了,然后就可以运行了。只是有报错。可能还是哪里编码不对吧。
对了,代码开头的reload和设置utf-8的两句,我也注释掉了。。

3f5e79

发件人邮箱登陆密码要设置为邮箱的授权码才行,楼主!

F4d2c5
lovesoo · #21 · 2017年12月05日 作者
3f5e79xiaoqiangzq 回复

我直接用账号密码就可以的 网易163邮箱

D99fd3
F4d2c5lovesoo 回复

速度👍
有一点小问题,nose_html_reporting的init中,引入了StringIO,在py3中,没有这个模块了。应该引入io,使用io.StringIO就可以了。
另外,我看邮件中中文是正常显示的。但是如果直接打开html文件的话,中文却是乱码的哦,这个怎么破呢?

另外,关于授权码,163邮箱可以打开或关闭授权码,开了就得使用授权码,没开就使用密码。QQ的话,好像就必须使用授权码了。

F4d2c5
lovesoo · #23 · 2017年12月05日 作者
D99fd3Donly 回复

是的,之前插件的问题就是StringIO,改插件源码相对比较麻烦,所以直接换了另外的插件了。
直接打开Html文件乱码,我这边使用Chrome浏览器看了是正常的。不知道你是用的什么浏览器,猜测应该是需要修改下页面的编码? (右键修改编码为UTF-8)

授权码的问题,应该就是你说的那样~👍

1925

mark,学习了

D99fd3
F4d2c5lovesoo 回复

我也是chrome,firefox也打开看了,都是乱码。。。
右键看编码已经是utf-8了

另外,刚刚运行第一遍的时候基本都是正确的,后面改了io,好多失败的。。只看test_q这一个,发现检查(大话西游)的时候失败了。但是我看返回的响应里面都是 大话西游之xxx 之类的。不知道是不是那个检查的语句问题,还是我这边的其他问题。

F4d2c5
lovesoo · #26 · 2017年12月05日 作者

报错应该是导出html报告插件的Python 3兼容性问题,麻烦看下上面的置顶帖(又...换了个插件)。

搜索“周星驰,大话西游”报错,是因为返回的第一个结果是“西游降魔篇”,结果校验时这里我目前只校验了第一个结果与搜索词是否匹配,“西游降魔篇”与“大话西游”不匹配,所以报错了。

D99fd3

装了新插件啦。并且也执行了pip uninstall nose-html-reporting。。

F4d2c5
lovesoo · #28 · 2017年12月05日 作者
D99fd3Donly 回复

还有问题嘛~现在😂

D99fd3
F4d2c5lovesoo 回复

除了报告乱码,暂时没有其他问题。
剩下的就是好好来消化你这些代码了。才开始学习接口自动化,nosetest这个框架也不熟悉,json也不熟悉,所以要学习的很多呢!!多谢你给指了一个方向!

F4d2c5
lovesoo · #30 · 2017年12月05日 作者
D99fd3Donly 回复

额,报告乱码的问题我已经解决了啊,看我最新上传的代码和置顶的回复贴~😄

D99fd3
F4d2c5lovesoo 回复

那就没有问题了。。。是我没有重新下载py代码导致。。

F4d2c5
lovesoo · #32 · 2017年12月05日 作者
D99fd3Donly 回复

OK~👌

88ef08


这同一个test的view点击后都是展开第一个的div,尤其那种失败的没法看详情啊

F4d2c5
lovesoo · #34 · 2017年12月05日 作者
88ef08fmhying 回复

我这边看了下是OK的~也有可能是nose-html-reporting插件的bug~

还是换nose-htmloutput这个插件吧😂

F4d2c5 lovesoo C/S 架构系统自动化测试入门 中提及了此贴 12月06日 14:54
36楼 已删除
88ef08

好了,万分感谢~~~

3f5e79

楼主,能说下yield的作用么?我没理解到!

F4d2c5
lovesoo · #39 · 2017年12月11日 作者
3f5e79xiaoqiangzq 回复

可以参考我之前写的博客文章:http://www.cnblogs.com/lovesoo/p/7735380.html
官方文档:http://nose.readthedocs.io/en/latest/writing_tests.html

简单来说就是Nose支持测试方法或函数是生成器(使用yield关键字定义),Nose每次执行测试时会迭代函数生成器,为每一个yiled的tuple创建一个测试用例。

11877
F4d2c5lovesoo 回复

我的天啊,我是刚学python,我一直再看python的yield,看的一脸懵逼,我还想呢返回个元组干啥。。。。
nose有啥好的中文资料吗?
还有个问题,我看网上说pytest好像更好一些,这个一般怎么选择呢,谢谢

F4d2c5
lovesoo · #41 · 2017年12月14日 作者
11877Pastel 回复

框架的选择具体可以参考如下文章:
https://blog.zengrong.net/post/2170.html
https://wiki.python.org/moin/PythonTestingToolsTaxonomy
就我自己而言,nose是最简单的,而且与pycharm配合特别好用~😳

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册