FavoriteLoading
0

接口自动化思路

写在开头: 技术渣做接口自动化,大神们请轻喷!多提提优化方案和问题点。

以前做接口测试一直通过postman 和 soapUI来做,Postman 是Chrome的一个插件Case多了不好管理,同时执行起来麻烦,得一个一个去点击执行,平时做调试可以用用真正用来做接口自动化不合适。
SoapUI (改名叫Ready!API)是个不错的工具,同时支持了soap类型和rest 类型的接口,而且还支持安全,性能等测试,当然它是个商业工具,高级功能都是需要收费的,想那啥也是可以的,但是工具提供了方便同样可扩展性差了点,而且我经常遇到莫名其妙的工具问题,也许是因为我用的是那啥版本,稳定性差吧。
也是有人直接用Jmeter 或者loadrunner 来做接口自动化的,当然也是行的当用例管理上也是较为麻烦,有个框架robot framework,关键字驱动来做接口也是一朋友一再推荐的做法,可惜我对python 不熟悉,尽管上手容易我还是放弃。
现在我改用这么一套思路在做,因为目前我的接口协议都是http的,我就干脆直接用java的HttpClient,然后接口返回是json格式,我就引入了json-lib来方便解析获取,同样因为需要跟数据库交互所以又引入了MyBatis,同时用例还是沿用TestNG ,为了更方便管理接口(地址,路径,参数等等)又通过excel来管理接口,通过excel来驱动测试。 这样下来整个项目就涉及了 httpclient+json+mybaits+testng+poi(excel)+log4j等框架包。

在这过程做了一些封装一些主要代码如下:
对httpclient 封装,只要把接口的完整请求传进来如果请求正常,就会return 的接口返回的json:


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
<span class="kd">public</span> <span class="kd">static</span> <span class="n">JSON</span> <span class="nf">getAPI</span><span class="p">(</span><span class="n">URI</span> <span class="n">uri</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">URISyntaxException</span><span class="o">,</span> <span class="n">IOException</span> <span class="o">{</span>

        <span class="n">CloseableHttpClient</span> <span class="n">httpclient</span> <span class="o">=</span> <span class="n">HttpClients</span><span class="o">.</span><span class="na">createDefault</span><span class="o">();</span>

        <span class="k">try</span> <span class="o">{</span>
            <span class="n">httpget</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HttpGet</span><span class="o">(</span><span class="n">uri</span><span class="o">);</span>
            <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"执行API请求"</span> <span class="o">+</span> <span class="n">httpget</span><span class="o">.</span><span class="na">getRequestLine</span><span class="o">());</span>
            <span class="n">ResponseHandler</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">responseHandler</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ResponseHandler</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;()</span> <span class="o">{</span>
                <span class="kd">public</span> <span class="n">String</span> <span class="n">handleResponse</span><span class="o">(</span>
                        <span class="kd">final</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">ClientProtocolException</span><span class="o">,</span> <span class="n">IOException</span> <span class="o">{</span>
                    <span class="kt">int</span> <span class="n">status</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="na">getStatusLine</span><span class="o">().</span><span class="na">getStatusCode</span><span class="o">();</span>
                    <span class="k">if</span> <span class="o">(</span><span class="n">status</span> <span class="o">&gt;=</span> <span class="mi">200</span> <span class="o">&amp;&amp;</span> <span class="n">status</span> <span class="o">&lt;</span> <span class="mi">300</span><span class="o">)</span> <span class="o">{</span>
                        <span class="n">HttpEntity</span> <span class="n">entity</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="na">getEntity</span><span class="o">();</span>
                        <span class="k">return</span> <span class="n">entity</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">EntityUtils</span><span class="o">.</span><span class="na">toString</span><span class="o">(</span><span class="n">entity</span><span class="o">)</span> <span class="o">:</span> <span class="kc">null</span><span class="o">;</span>
                    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                        <span class="n">log</span><span class="o">.</span><span class="na">error</span><span class="o">(</span><span class="s">"请求错误,状态码为:"</span><span class="o">+</span><span class="n">response</span><span class="o">.</span><span class="na">getStatusLine</span><span class="o">().</span><span class="na">getStatusCode</span><span class="o">());</span>
                        <span class="k">throw</span> <span class="k">new</span> <span class="n">ClientProtocolException</span><span class="o">(</span><span class="s">"意外的状态返回: "</span> <span class="o">+</span> <span class="n">status</span><span class="o">);</span>
                    <span class="o">}</span>
                <span class="o">}</span>
            <span class="o">};</span>
            <span class="n">String</span> <span class="n">responseBody</span> <span class="o">=</span> <span class="n">httpclient</span><span class="o">.</span><span class="na">execute</span><span class="o">(</span><span class="n">httpget</span><span class="o">,</span> <span class="n">responseHandler</span><span class="o">);</span>
            <span class="n">JSONObject</span> <span class="n">dataObject</span> <span class="o">=</span> <span class="n">JSONObject</span><span class="o">.</span><span class="na">fromObject</span><span class="o">(</span><span class="n">responseBody</span><span class="o">);</span>
            <span class="k">return</span> <span class="n">dataObject</span><span class="o">;</span>
        <span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
            <span class="n">httpclient</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
        <span class="o">}</span>

    <span class="o">}</span>

那请求可以发起了,接口URL 怎么来? 刚说通过excel来管理接口了,例如我新建了下面这么个文件:

TID 用来标识我需要读取哪行数据,TName仅仅做说明这个接口是什么接口,Method 来表示接口是什么类型,根据不同类型做调用不同的httpclient 封装方法,然后后面就是去拼接接口的URL:
拼接URL的关键代码如下:


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
41
42
43
 <span class="cm">/**
     * 请求链接拼接
     *
     * @param tid        哪一行的excel数据
     * @param parameters 参数
     * @return uri
     */</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="n">URI</span> <span class="n">returnURI</span><span class="o">(</span><span class="n">String</span> <span class="n">tid</span><span class="o">,</span> <span class="n">String</span><span class="o">...</span> <span class="n">parameters</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">String</span> <span class="n">path</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"user.dir"</span><span class="o">)</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="s">"src"</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="s">"main"</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="s">"resources"</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="s">"excel"</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="s">"api.xls"</span><span class="o">;</span>
        <span class="n">ExcelEngine</span><span class="o">.</span><span class="na">filepath</span> <span class="o">=</span> <span class="n">path</span><span class="o">;</span>
        <span class="n">ExcelEngine</span><span class="o">.</span><span class="na">sheetname</span> <span class="o">=</span> <span class="s">"api"</span><span class="o">;</span>
        <span class="c1">// 从excel 拿数据</span>
        <span class="n">List</span> <span class="n">apiData</span> <span class="o">=</span> <span class="n">getApiData</span><span class="o">(</span><span class="n">tid</span><span class="o">);</span>
        <span class="n">String</span> <span class="n">getorpost</span> <span class="o">=</span> <span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">apiData</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">2</span><span class="o">)).</span><span class="na">toLowerCase</span><span class="o">();</span>
<span class="c1">//        System.out.println(getorpost);</span>
        <span class="n">String</span> <span class="n">scheme</span> <span class="o">=</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">apiData</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">3</span><span class="o">);</span>
        <span class="n">String</span> <span class="n">apiHost</span> <span class="o">=</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">apiData</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">4</span><span class="o">);</span>
        <span class="n">String</span> <span class="n">apiPath</span> <span class="o">=</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">apiData</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="mi">5</span><span class="o">);</span>
        <span class="c1">// URI 拼接</span>
        <span class="n">StringBuffer</span> <span class="n">stringBuffer</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuffer</span><span class="o">(</span><span class="n">scheme</span> <span class="o">+</span> <span class="s">"://"</span> <span class="o">+</span> <span class="n">apiHost</span> <span class="o">+</span> <span class="n">apiPath</span> <span class="o">+</span> <span class="s">"?"</span><span class="o">);</span>
        <span class="n">HashMap</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="n">hashmap</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HashMap</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">p</span> <span class="o">&lt;</span> <span class="n">parameters</span><span class="o">.</span><span class="na">length</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">hashmap</span><span class="o">.</span><span class="na">put</span><span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">apiData</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">p</span> <span class="o">+</span> <span class="mi">6</span><span class="o">),</span> <span class="n">parameters</span><span class="o">[</span><span class="n">p</span><span class="o">]);</span>
            <span class="n">p</span> <span class="o">=</span> <span class="n">p</span> <span class="o">+</span> <span class="mi">1</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="n">hashmap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"autoKey"</span><span class="o">,</span> <span class="n">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">Parameters</span><span class="o">.</span><span class="na">timeStamp_Long</span><span class="o">()));</span>
<span class="c1">//        int i = hashmap.size();</span>
<span class="c1">//        System.out.println("map 大小" + i);</span>
        <span class="kt">int</span> <span class="n">num</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="c1">//        System.out.println("map 里面的值" + hashmap.entrySet());</span>
        <span class="k">for</span> <span class="o">(</span><span class="n">HashMap</span><span class="o">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="n">entry</span> <span class="o">:</span> <span class="n">hashmap</span><span class="o">.</span><span class="na">entrySet</span><span class="o">())</span> <span class="o">{</span>
            <span class="n">num</span><span class="o">++;</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">num</span> <span class="o">==</span> <span class="n">hashmap</span><span class="o">.</span><span class="na">size</span><span class="o">())</span> <span class="o">{</span>
                <span class="n">stringBuffer</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">entry</span><span class="o">.</span><span class="na">getKey</span><span class="o">()</span> <span class="o">+</span> <span class="s">"="</span> <span class="o">+</span> <span class="n">entry</span><span class="o">.</span><span class="na">getValue</span><span class="o">());</span>
            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                <span class="n">stringBuffer</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">entry</span><span class="o">.</span><span class="na">getKey</span><span class="o">()</span> <span class="o">+</span> <span class="s">"="</span> <span class="o">+</span> <span class="n">entry</span><span class="o">.</span><span class="na">getValue</span><span class="o">()</span> <span class="o">+</span> <span class="s">"&amp;"</span><span class="o">);</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="n">String</span> <span class="n">url</span> <span class="o">=</span> <span class="n">stringBuffer</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
        <span class="n">URI</span> <span class="n">uri</span> <span class="o">=</span> <span class="n">URI</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">url</span><span class="o">);</span>
        <span class="k">return</span> <span class="n">uri</span><span class="o">;</span>
    <span class="o">}</span>

现在接口的URL拼接完成了,请求也发起了,也可以拿到返回的json数据了,最后就得对返回的数据做校验了,这里我是重新封装了下TestNG 提供的Assert类为TaquAssert类,其实没做多大改变加了几个方法而已,下面是一个完整的登陆例子:


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
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">LoginTest</span> <span class="o">{</span>
    <span class="kd">static</span> <span class="n">LoggerControler</span> <span class="n">log</span> <span class="o">=</span> <span class="n">LoggerControler</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="n">LoginTest</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
    <span class="c1">// accounts 表</span>
    <span class="n">AccountsTest</span> <span class="n">accountsTest</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AccountsTest</span><span class="o">();</span>

    <span class="n">String</span> <span class="n">tid</span> <span class="o">=</span> <span class="s">"v1_Account_login"</span><span class="o">;</span>

    <span class="nd">@Test</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="n">loginSuccess</span><span class="o">()</span> <span class="o">{</span>
        <span class="c1">// 发起api请求</span>
        <span class="n">JSONObject</span> <span class="n">json</span> <span class="o">=</span> <span class="n">ApiEngine</span><span class="o">.</span><span class="na">taquAPI</span><span class="o">(</span><span class="n">tid</span><span class="o">,</span> <span class="s">"username"</span><span class="o">,</span> <span class="s">"password"</span><span class="o">);</span>
        <span class="c1">// 打印出json</span>
        <span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="n">json</span><span class="o">);</span>

        <span class="c1">// 通过api获取该用户的account_id,然后查询Accounts表</span>
        <span class="n">String</span> <span class="n">account_id</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="na">getJSONObject</span><span class="o">(</span><span class="s">"info"</span><span class="o">).</span><span class="na">getJSONObject</span><span class="o">(</span><span class="s">"data"</span><span class="o">).</span><span class="na">getString</span><span class="o">(</span><span class="s">"account_id"</span><span class="o">);</span>
        <span class="n">Accounts</span> <span class="n">accounts</span> <span class="o">=</span> <span class="n">accountsTest</span><span class="o">.</span><span class="na">byAccount_id</span><span class="o">(</span><span class="n">Integer</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">account_id</span><span class="o">));</span>

        <span class="c1">// 校验返回的 状态是不是 success.</span>
        <span class="n">String</span> <span class="n">response_status</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="na">getString</span><span class="o">(</span><span class="s">"response_status"</span><span class="o">);</span>
        <span class="n">TaquAssert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"校验response_status"</span><span class="o">,</span> <span class="s">"success"</span><span class="o">,</span> <span class="n">response_status</span><span class="o">);</span>

        <span class="c1">// 从数据库获取用户名和接口返回的用户名做对比检查是否一致</span>
        <span class="n">String</span> <span class="n">account_name_sql</span> <span class="o">=</span> <span class="n">accounts</span><span class="o">.</span><span class="na">getAccount_name</span><span class="o">();</span>
        <span class="n">String</span> <span class="n">account_name_api</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="na">getJSONObject</span><span class="o">(</span><span class="s">"info"</span><span class="o">).</span><span class="na">getJSONObject</span><span class="o">(</span><span class="s">"data"</span><span class="o">).</span><span class="na">getString</span><span class="o">(</span><span class="s">"nickname"</span><span class="o">);</span>
        <span class="n">TaquAssert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"校验account_name"</span><span class="o">,</span> <span class="n">account_name_api</span><span class="o">,</span> <span class="n">account_name_sql</span><span class="o">);</span>

    <span class="o">}</span>
<span class="o">}</span>

后期还会把这块放到Jenkins环境去运行,之前把Jenkins环境搞坏了,苦逼还得去重搭建

OK 以上就是目前做接口自动化的大概思路,这其中肯定还有非常多需要去做优化的, 望各大神提提优化意见和方案,小弟不胜感激。

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

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

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

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

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