FavoriteLoading
0

Http 接口测试框架 (开源 + 已投入实际项目中)

相关链接

说明

由于部分内容涉及公司机密,已用字母替换,不影响阅读

实际效果

  • 验证1000个接口平均耗时6s(看机器配置及网速)
  • 第一次投入使用,马上发现5个接口异常并且该验证过程不到30s的时间

框架的下一步

  • 目前已兼容我们公司所有app

  • response body全字段验证(含字段类型)

    • 已有思路
  • 字段变化导致2个大问题

    • 由原本int(0/1)变成了布尔型
    • 时间戳长度由10位突然变成13位
  • 尽量避免日常监控中跑接口对外网数据/用户的影响

    • 目前做法是屏蔽相关接口
    • 目前状态
    • 跑接口时创建的数据id有变化,然而删除接口还是调用老的id去删除,导致数据删除不到
    • 改进
    • 拦截创建数据的response body取出对于id
    • 拦截删除接口request body,传入上一步拦截的id

最新框架图(红色部分未完成)

Http接口测试框架

部分代码

配置文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
<span class="err">http接口测试框架配置信息</span>

<span class="py">tester</span> <span class="p">=</span> <span class="s">tester</span>
<span class="py">project</span> <span class="p">=</span> <span class="s">A</span>
<span class="py">versionName</span> <span class="p">=</span> <span class="s">2.2.2</span>
<span class="py">versionCode</span> <span class="p">=</span> <span class="s">237</span>
<span class="py">host</span> <span class="p">=</span> <span class="s">a-webapi.test.b.com</span>
<span class="py">getTokenHost</span> <span class="p">=</span> <span class="s">http://a-webapi.test.b.com/api/System/GetToken</span>
<span class="py">loginHost</span> <span class="p">=</span> <span class="s">http://a-webapi.test.b.com/api/User/LoginV2</span>
<span class="py">loginInfo</span> <span class="p">=</span> <span class="s">Phone=13750199962&amp;Password=FGgIwe5oCdk%3D</span>
<span class="py">SessionsPath</span> <span class="p">=</span> <span class="s">D:</span><span class="se">\F</span><span class="s">iddler Sessions</span>
<span class="py">ApiURL</span> <span class="p">=</span> <span class="s">http://apihelper.b.com/Home/API/c</span>
<span class="c"># SpecialSessions &gt;&gt; 屏蔽的接口
</span><span class="py">SpecialSessions</span> <span class="p">=</span> <span class="s">['GetToken', 'LoginV2', 'LogOut', 'BookingV2']</span>

启动测试入口


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<span class="s">"""
运行api测试总入口
"""</span>

<span class="kn">import</span> <span class="nn">sessions.Request</span>


<span class="k">def</span> <span class="nf">launcher_api_test</span><span class="p">():</span>
    <span class="s">"""
    1.获取接口列表
    2.与本地sessions对比
    3.差异化文件,是否继续
    3.1否 继续录制接口
    3.2是 开始跑接口
    :return:
    """</span>
    <span class="n">r</span> <span class="o">=</span> <span class="n">sessions</span><span class="o">.</span><span class="n">Request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>  <span class="c"># 0 &gt;&gt; A    1 &gt;&gt; B</span>
    <span class="n">r</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">launcher_api_test</span><span class="p">()</span>

头部、登录接口


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    <span class="k">def</span> <span class="nf">__get_token_header</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">"""
        生成token头部
        :return:
        """</span>
        <span class="n">des</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__get_token_des</span><span class="p">()</span>
        <span class="n">arr</span> <span class="o">=</span> <span class="p">(</span><span class="n">des</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'systemType'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'Model'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'Release'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'DeviceId'</span><span class="p">],</span>
               <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'versionCode'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'versionName'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'AppBuild'</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'DeviceOS'</span><span class="p">],</span> <span class="s">"0"</span><span class="p">)</span>
        <span class="n">authorization</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">AUTHORIZATION_TOKEN</span> <span class="o">%</span> <span class="n">arr</span>
        <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">'Content-Type'</span><span class="p">:</span> <span class="s">'application/x-www-form-urlencoded; charset=utf-8'</span><span class="p">,</span> <span class="s">'Authorization'</span><span class="p">:</span> <span class="n">authorization</span><span class="p">}</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'getTokenHost'</span><span class="p">],</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)[</span><span class="s">'StatsCode'</span><span class="p">]</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
            <span class="n">data1</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)[</span><span class="s">'Data'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">time</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'Time'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">TOKEN_NAME</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'TokenName'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">TOKEN_VALUE</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'TokenValue'</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="s">"GetToken失败,请手动检查"</span><span class="p">)</span>
            <span class="n">utils</span><span class="o">.</span><span class="n">HandleJson</span><span class="o">.</span><span class="n">HandleJson</span><span class="o">.</span><span class="n">print_json</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__login_session</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">"""
        调用登录接口,这样后面的接口都能正常访问了
        :return:
        """</span>
        <span class="n">url_login</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'loginHost'</span><span class="p">]</span>
        <span class="n">headers</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__get_session_header</span><span class="p">(</span><span class="n">url_login</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'api/'</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
        <span class="n">data_login</span> <span class="o">=</span> <span class="s">r'</span><span class="si">%</span><span class="s">s'</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">conf</span><span class="p">[</span><span class="s">'loginInfo'</span><span class="p">]</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url_login</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">data_login</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)[</span><span class="s">'StatsCode'</span><span class="p">]</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
            <span class="n">data1</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)[</span><span class="s">'Data'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">uId</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">head_uid</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">uName</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'NickName'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">uPhone</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'Phone'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">SessionId</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'Sid'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">uType</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'UserType'</span><span class="p">]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span> <span class="o">=</span> <span class="n">data1</span><span class="p">[</span><span class="s">'UID'</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="s">"登录失败,请手动检查"</span><span class="p">)</span>
            <span class="n">utils</span><span class="o">.</span><span class="n">HandleJson</span><span class="o">.</span><span class="n">HandleJson</span><span class="o">.</span><span class="n">print_json</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>

接口片段


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Request url: a-webapi.test.b.com/api/Circle/AddCancelCollectCircle
Request header: POST /api/Circle/AddCancelCollectCircle HTTP/1.1
Host: a-webapi.test.b.com
Accept: text/json
Authorization: Digest t="2016-08-04 16:41:19",SystemType="2",u="Circle/AddCancelCollectCircle",r="59e93eb1a6625adc6bff5ede5945a2f7",DeviceId="ffffffff-8416-49fe-3fdc-6ee400000000",Model="SM-N9100",DeviceOS="22",Release="5.1.1",VersionName="2.2.2",VersionCode="239",PushToken="",uId="3353",uName="123456ejz",uPhone="13750199962",SessionId="%2FZhckUf9%2Fd2soQZhYofjN021SdWUpLv0aW%2F3CJBr71vtOl1YHJda6J8p6P1hsQS0P3kqirm%2BtPs%3D",uType="1",bDChannelId="",bDUserId="",AppBuild="239",uUID="2255"
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 21
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.0.1

Request body: CircleId=6418&amp;IsAdd=1
Response code: 200
Response body: {"StatsCode":200,"Message":"收藏成功","Data":null,"Other":null}
Session end



Request url: a-webapi.test.b.com/api/Circle/AddCancelCollectCircle
Request header: POST /api/Circle/AddCancelCollectCircle HTTP/1.1
Host: a-webapi.test.b.com
Accept: text/json
Authorization: Digest t="2016-08-04 16:41:22",SystemType="2",u="Circle/AddCancelCollectCircle",r="26dcb55ee9ac79995c21656517c455e8",DeviceId="ffffffff-8416-49fe-3fdc-6ee400000000",Model="SM-N9100",DeviceOS="22",Release="5.1.1",VersionName="2.2.2",VersionCode="239",PushToken="",uId="3353",uName="123456ejz",uPhone="13750199962",SessionId="%2FZhckUf9%2Fd2soQZhYofjN021SdWUpLv0aW%2F3CJBr71vtOl1YHJda6J8p6P1hsQS0P3kqirm%2BtPs%3D",uType="1",bDChannelId="",bDUserId="",AppBuild="239",uUID="2255"
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 21
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.0.1

Request body: CircleId=6418&amp;IsAdd=0
Response code: 200
Response body: {"StatsCode":200,"Message":"取消收藏成功","Data":null,"Other":null}
Session end

接口列表

接口列表

你需要做的

  • 环境配置

    • Python 3.x
    • fiddler一枚(配置抓取手机请求)
    • PyCharm
  • token/session替换

    • 替换成你们项目对应的token等
    • 修改配置文件
    • 修改response body json 判断逻辑
  • 替换fiddler js

    • 项目根目录的fiddler js整个文件内容替换fiddler的js
    • 打开fiddler的Customize Rules功能
    • 删除所有内容,并把fiddler js内容全部拷贝进去
    • 修改拦截的host等信息
    • fiddler保存请求

fiddler js 自定义信息


1
2
3
4
5
6
7
8
    <span class="c1">//自定义参数设置</span>
    <span class="kr">public</span> <span class="kr">static</span> <span class="kd">var</span> <span class="nx">filterUrl</span> <span class="o">=</span> <span class="s2">"a-webapi.test.b.com"</span><span class="p">;</span>
    <span class="kr">public</span> <span class="kr">static</span> <span class="kd">var</span> <span class="nx">filePath</span> <span class="o">=</span> <span class="s2">"D:\\Fiddler Sessions\\Api\\"</span><span class="p">;</span>
    <span class="kr">public</span> <span class="kr">static</span> <span class="kd">var</span> <span class="nx">filePathForRequested</span> <span class="o">=</span> <span class="s2">"D:\\Fiddler Sessions\\Requested.txt"</span><span class="p">;</span>
    <span class="kr">public</span> <span class="kr">static</span> <span class="kd">var</span> <span class="nx">filePathForErrorResponse</span> <span class="o">=</span> <span class="s2">"D:\\Fiddler Sessions\\ErrorResponse.txt"</span><span class="p">;</span>
    <span class="kr">public</span> <span class="kr">static</span> <span class="kd">var</span> <span class="nx">filePathForVerifyRequset</span> <span class="o">=</span> <span class="s2">"D:\\Fiddler Sessions\\VerifyRequset.txt"</span><span class="p">;</span>
    <span class="kr">public</span> <span class="kr">static</span> <span class="kd">var</span> <span class="nx">filePathForRemoveSession</span> <span class="o">=</span> <span class="s2">"D:\\Fiddler Sessions\\RemoveSession.txt"</span><span class="p">;</span>
    <span class="kr">public</span> <span class="kr">static</span> <span class="kd">var</span> <span class="nx">filePathForAddSession</span> <span class="o">=</span> <span class="s2">"D:\\Fiddler Sessions\\AddSession.txt"</span><span class="p">;</span>
  • github拉取代码
  • 欢迎一起交流

GitHub

框架地址

声明:本文转载自 TesterHome 移动测试社区,作者为 TesterHome 移动测试社区,原文网址:https://testerhome.com/topics/5631

最后编辑于:2016/11/16作者: 聚合

聚合类文章源自互联网, 感谢原作者的无私分享。

关注微信公众号 – 聚合软件测试类精华

关注微信公众号 – 聚合软件测试类精华