美文网首页编程技术类
基于Python实现简单的接口自动化

基于Python实现简单的接口自动化

作者: c4a1d989518e | 来源:发表于2017-06-15 18:10 被阅读849次

为什么要用Python实现接口自动化?

使用requests+unittest很容易实现接口自动化测试,而且requests的api已经非常人性化,通过封装以后(特别是针对公司内特定接口),再加上对一些常用工具的封装,可以进一步提高业务脚本编写效率。

搭建环境

确保Python版本是2.7以上

pip install flask
pip install requests

上一篇文章写了可以用Flask框架写接口,这次我们就正好用上了。写好接口以后,就可以用requests去测试了。

接口代码

新建一个demo.py文件,用flask实现两个http接口,一个用于登录,一个用于登录后的查询。

from flask import Flask,request,session,jsonify

USERNAME='admin'
PASSWORK='123456'

app=Flask(__name__)
app.secret_key='pithy'

@app.route('/login',methods=['GET','POST'])
def login():
    error=None
    if request.method=='POST':
        if request.form['username']!=USERNAME:
             error='Invalid username'
        elif request.form['password']!=PASSWORD:
             error='Invalid password'
        else:
             session['logged_in']=True
             return jsonify({'code':200,'msg':'success'})
    return jsonify({'code':401,'msg':'error'})

@app.route('/info',methods=['get'])
def info():
    if not session.get('logged_in'):
        return jsonify({'code':401,'msg':'please login !!'})
    return jsonify({'code':200,'msg':'success','data':'info'})

if __name__=='__main__':
    app.run(debug=True)

启动的命令

python demo.py

从上面的代码中可以看出:

  • 请求url为/login请求方法为post

  • 详情接口URL为/info请求方法为get

编写接口测试代码

脚本实现为:

import requests
import unittest

class TestLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.login_url='http://127.0.0.1:5000/login'
        cls.info_url='http://127.0.0.1:5000/info'
        cls.username='admin'
        cls.password='123456'

    def test_login(self):
        """测试登录"""
        data={'username':self.username,'password':self.password}
        response=requests.post(self.login_url,data=data).json()
        assert response['code']==200
        assert response['msg']=='success'

    def test_info(self):
        """测试info接口"""
        data={'username':self.username,'password':self.password}
        response_cookies=requests.post(self.login_url,data=data).cookies
        session=response_cookies.get('session')
        assert session
        info_cookies={'session':session}
        response=requests.get(self.info_url,cookies=info_cookies).json()
        assert response['code']==200
        assert response['msg']=='success'
        assert response['data']=='info'

代码优化

封装接口调用,写完这个测试登录脚本,你或许会发现,在整个项目的测试过程,登录可能不止用到一次,如果每次都这样写,会不会太冗余了?下面做一个简单的封装,把登录接口的调用封装到一个方法里,把调用参数暴露出来,示例脚本如下:

import requests
import unittest

try:
    from urlparse import urljoin
except ImportError:
    from urllib.parse import urljoin

class DemoApi(object):
    def __init__(self,base_url):
        self.base_url=base_url
    def login(self,username,password):
        """登录接口
        :param username:用户名
        :param password:密码
        """
        url=urljoin(self.base_url,'login')
        data={'username':username,'password':password}
        return requests.post(url,data=data).json()

    def get_cookies(self,username,password):
        """
        获取登录cookies

        """
        url=urljoin(self.base_url,'login')
        data={'username':username,'password':password}
        return requests.post(url,data=data).cookies

    def info(self,cookies):
        """
        详情接口

        """
        url=urljoin(self.base_url,'info')
        return requests.get(url,cookies=cookies).json()

class TestLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.base_url='http://127.0.0.1:5000'
        cls.username='admin'
        cls.password='123456'
        cls.app=DemoApi(cls.base_url)

    def test_login(self):
        """
        测试登录
        """
        response=self.app.login(self.username,self.password)
        assert response['code']==200
        assert response['msg']=='success'

    def test_info(self):
        “”“
        测试获取设备详情
        """
        cookies=self.app.get_cookies(self.username,self.password)
        response=self.app.info(cookies)
        assert response['code']==200
        assert response['msg']=='success'
        assert response['data']=='info'

在上面的版本中,我们不但把登录接口的调用封装成了一个实例方法,实现了复用,而且还把host(self.base_url)提取出来。

进一步改进:让登录之后,登录接口的http响应会把session以cookie的形式set到客户端,之后的接口都会使用此session去请求,还有就是在接口调用过程中,希望可以把日志打印出来。

解决方法:使用requests库里的同一个Session对象,可解决,示例代码如下:

import unittest
from pprint import pprint
from requests.sessions import Session

try:
    from urlparse import urljoin
except ImportError:
    from urllib.parse import urljoin

class DemoApi(object):
    
    def __init__(self,base_url):
        self.base_url=base_url
        #创建session实例
        self.session=Session()

    def login(self,username,password):
        ”“”
        登录接口
        :param username:用户名
        :param password:密码
        """
        url=urljoin(self.base_url,'login')
        data={'username':username,'password':password}
        response=self.session.post(url,data=data).json()

print('\n************************************')
        print(u'\n1、请求url:\n%s'%url)
        print(u'\n2、请求头信息:')

pprint(self.session.headers)
        print(u'\n3、请求头信息:')
        pprint(data)
        print(u'\n4、响应:')
        pprint(response)
        return response

    def info(self):
        """
        详情接口
        """
        url=urljoin(self.base_url,'info')
        response=self.session.get(url).json()

print('\n********************************')
        print(u'\n1、请求url:\n%s'%url)
        print(u'\n2、请求头信息:')
pprint(self.session.headers)
        print(u'\n3、请求cookies:')
        pprint(data)
        print(u'\n4、响应:')
        pprint(response)
        return response


class TestLogin(unittest.TestCase):
    @classsmethod
    def setUpClass(cls):
        cls.username='admin'
        cls.password='123456'
        cls.app=DemoApi(cls.base_url)

    def test_login(self):
        """
        测试登录
        """
        response=self.app.login(self.username,self.password)
        assert response['code']==200
        assert response['msg']=='success'

    def test_info(self):
        """
        测试获取详情信息
        """
self.app.login(self.username,self.password)
        response=self.app.info()
        assert response['code']==200
        assert response['msg']=='success'
        assert response['data']=='info'

上面的代码,我们把多个相关接口调用封装到了一个类中,使用同一个requests Session实例来保持cookies,并且在调用过程中打印出了日志。但是代码看着还是不舒服,在每个方法里,我们都需要写一遍print 1、2、3要拼url、还要很多细节等等,但其实我们真正需要做的只是拼接出关键参数(url参数、body参数或者传入headers信息),可不可以只需要定义必须的信息,然后把其他共性的东西都封装起来,统一放到一个地方去管理?

在这里就需要使用Python的装饰器功能,把公共特性封装到装饰器中去实现。
示例代码

扩展

接下来我们还可以做什么来丰富呢?

  • 非HTTP协议接口
  • 测试用例编写
  • 配置文件管理
  • 测试数据管理
  • 工具类编写
  • 测试报告生成
  • 持续集成

关于测试报告

目前python的主流单元测试框均有report插件

  • pytest:推荐使用pytest-html和allure pytest。
  • unittest:推荐使用HTMLTestRunner。

测试用例编写原则:

  • 原子性:每个用例保持独立,彼此不耦合,以降低干扰。

  • 专一性:一个用例应该专注于验证一件事情,而不是做很多事情,一个测试点不要重复验证。

  • 稳定性:绝大多数用例应该是非常稳定的,也就是说不会经常因为除环境以外的因素挂掉,因为如果在一个测试项目中有很多不稳定的用例的话,测试结果就不能很好的反应项目质量。

  • 分类清晰:有相关性的用例应写到一个模块或一个测试类里,这样做即方便维护,又提高了报告的可读性。

文章参考:
饿了么技术社区-GitChat(他们用的框架为pithy)

相关文章

网友评论

    本文标题:基于Python实现简单的接口自动化

    本文链接:https://www.haomeiwen.com/subject/sztuqxtx.html