zoukankan      html  css  js  c++  java
  • 如何利用cURL和python对服务端和web端进行接口测试

    工具描述

    cURL是利用URL语法在命令行方式下工作的文件传输工具,是开源爱好者编写维护的免费工具,支持包括Windows、Linux、Mac等数十个操作系统,最新版本为7.27.0,但是我推荐大家使用7.26.0,从这里可以下载7.26.0版本。

    以下是官方介绍的翻译: cURL是一个使用URL语法来传输数据的命令行工具,支持DICT,FILE,FTP,FTPS,GOPHER,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,POP3,POP3S,RTMP,RTSP,SCP,SFTP,SMTP,SMTPS,Telnet和TFTP。 cURL支持SSL证书,HTTP POST,HTTP PUT,FTP上传,HTTP基础表单上传,代理,cookies,用户+密码身份验证(Basic, Digest, NTLM, Negotiate, kerberos...),恢复文件传输,隧道代理等等。

    Python是一种面向对象、直译式计算机程序设计语言,由Guido van Rossum于1989年底发明,它的强大和易用就无需多做说明了,在web开发中或者对开发速度要求较高的开发中应用十分广,不过因为属于脚本类语言,它的性能始终比不上C++、C等语言。

    本文主要利用实例说明这两款工具的在测试中的部分用途,更多用法留待大家继续探索。

    应用场景

    使用cURL模拟客户端对服务端进行查询 

    在进行接口测试时,应该先找开发人员提供接口列表和对应参数,这样测试的时候就可以验证测试方法是否正确,不过如果可以用浏览器模拟操作的话,也可以自己先试试的,后面的例子会提到。 

    首先使用客户端访问需要测试的服务端接口,用wireshark抓包结果如下:

    把查询字符串以multipart方式post数据到服务器的file_health_info.php接口。

    Tips:

    Windows版的cURL不像Linux或者Mac一样属于系统自带工具,需要下载,如果要在命令提示符下使用就需要跳转到工具所在目录下才能运行,十分麻烦,我们可以直接把这个工具文件放到Windows目录下,这样无论在哪个目录都可以直接使用“curl”命令运行工具了。

    cURL默认就是以post方式发送数据的,所以只需要加入multipart方式就可以了,-F在cURL帮助中的解释是:

    -F,  --form CONTENT  Specify HTTP multipart POST data (H)
        --form-string STRING  Specify HTTP multipart POST data (H)
        --ftp-account DATA  Account data string (F)
        --ftp-alternative-to-user COMMAND  String to replace "USER [name]" (F)
        --ftp-create-dirs  Create the remote dirs if not present (F)
        --ftp-method [MULTICWD/NOCWD/SINGLECWD] Control CWD usage (F)
        --ftp-pasv      Use PASV/EPSV instead of PORT (F)

    Specify HTTP multipart POST data正好满足我们的要求,所以模拟的语句是:

    curl -F "newmd5=3bcad21af5f17c1fbff419137297c942###25016566###d: est.exe###1###" http://172.22.54.22/file_health_info.php

    后面的都是参数,测试前就要找开发确认好。

    不过因为服务端支持以gzip方式返回数据,所以我们还可以在请求中加入—compressed参数,即是:

    curl --compressed -F "newmd5=3bcad21af5f17c1fbff419137297c942###25016566###d: est.exe###1###" http://172.22.54.22/file_health_info.php

    为了更好判断服务端接口是否正常,除了对返回数据进行判断外,我们还需要对服务端返回的数据包头进行解析,所以还可以在cURL请求中加入-i参数,最终这个测试语句就变为:

    curl –i --compressed -F "newmd5=3bcad21af5f17c1fbff419137297c942###25016566###d: est.exe###1###" http://172.22.54.22/file_health_info.php

    模拟完成后就要考虑判断返回值的事了,我们首先在命令提示符下运行这个语句,看看返回值。

    运行以上命令后,返回的数据如下:

    HTTP/1.1 100 Continue
    HTTP/1.1 200 OK
    Date: Fri, 24 Aug 2012 07:47:45 GMT
    Content-Type: application/xml
    Transfer-Encoding: chunked
    Connection: keep-alive
    Server: 360 web server
    Content-Encoding: gzip
        <?xml version="1.0" encoding="GBK" ?>
          <ret>
          <retinfo code="0" msg="Operation success" total="1" success="1" empty="0" cost="999.92752075195"/>
          <softs>
            <soft>
             <md5>3bcad21af5f17c1fbff419137297c942</md5>
             <sha1></sha1>
             <level>4040</level>
             <e_level>40.3</e_level>
             <size></size>
             <soft_name><![CDATA[]]> </soft_name>
             <describ><![CDATA[]]></describ>
             <file_desc><![CDATA[]]></file_desc>
             <upload>0</upload>
             <attr_upload>2</attr_upload>
             <class><![CDATA[private]]></class>
             <malware><![CDATA[cloud.virus]]></malware>
             <is_sys_file>0</is_sys_file>
             <is_rep>0</is_rep>
             <age>0</age>
             <pop>0</pop>
       </soft>
          </softs>
          </ret>

      数据包包头是常见的,一般来说,我们只要判断包头中含有“HTTP/1.1 200 OK”就可以确定服务端正常返回了数据。另外从内容可以看到这是一个xml格式的数据包,我们只需要判断是否存在关键的字段即可,比如<level>,确定这些之后我们就可以在python中添加如下案例代码了:

    首先运行指定的curl命令:

    response = os.popen('''curl -i --compressed -F "newmd5=3bcad21af5f17c1fbff419137297c942###25016566###d: est.exe###1###" http://172.22.54.31/file_health_info.php

    然后判断返回值中是否存在我们想要的字段:

    self.assertNotEqual(response.find('HTTP/1.1 200 OK'),-1)

    self.assertNotEqual(response.find('<level>'),-1)

    上面的内容看起来差不多可以了,但实际还不够严谨,因为服务端返回的这些数据是从数据库中获取的,所以我们还需要查询数据库获取指定值,判断是否和数据包中的一致,比如<level>:

    首先使用python登录数据库服务器:

    conn = MySQLdb.connect(host='172.22.54.31', user='user',passwd='test321',db='cloud')

    cursor = conn.cursor()

    count = cursor.execute('SELECT plevel FROM file where md5="3bcad21af5f17c1fbff419137297c942"')

    result = cursor.fetchone()

    然后判断返回值中的level是否数据库中的值:

    self.assertNotEqual(response.find('''<level>%s</level>'''%result[0]),-1)

    测试时除了使用cURL等工具进行模拟,还可以自己用python或其他语言写代码进行post数据,不过当时简单起见所以就选择了用cURL测试。

    使用cURL模拟控制台登录

    说到模拟登录或者模拟点击,很多同学可能直接联想到QTP等模拟界面操作的工具,事实上这种工具有一个很大的弊端是太依赖控件,如果界面控件变了,那么可能整个脚本就无效了,现在的程序设计都倾向界面逻辑分离,这样修改界面时就不会动到底下的功能接口,开发人员可以随时修改界面控件,如果还是采取QTP等模拟点击的方法测试,结果可能是事倍功半的,如果测试时直接点用接口就可以避免这种问题。

    下面的例子是模拟控制台登录的,登录URL为:

    http://172.22.54.31:8888/cloud/index.php?r=site/login ,首先使用浏览器登录一次,看看实际效果如何。

    Tips:

    测试php或其他web程序时建议使用chrome,因为它自带的Developer Tools十分好用,当然firefox或者IE9也有类似的工具,看个人习惯吧。按F12打开工具,选择Network标签页,然后输入用户名、密码点击登录,这时Network下方会显示登录过程中浏览器想控制台请求的所有数据,包括请求类型、表单数据等,这些是我们模拟操作的数据来源。

    从上图可以获取几个重点信息:请求URL、请求类型、数据类型、数据内容、并且支持gzip压缩等。我们用curl模拟如下:

    curl -i --compressed http://172.22.54.31:8888/cloud/index.php?r=site/login -d “username=admin” -d “userpass=admin”

    使用-i和—compressed的原因再上一个例子已经说了,这里不再赘述,重点是后面的-d,它在官方帮助的解释是:

    -d,    --data DATA     HTTP POST data (H)
         --data-ascii DATA  HTTP POST ASCII data (H)
         --data-binary DATA  HTTP POST binary data (H)
         --data-urlencode DATA  HTTP POST data url encoded (H)
         --delegation STRING GSS-API delegation permission
         --digest        Use HTTP Digest Authentication (H)
         --disable-eprt  Inhibit using EPRT or LPRT (F)
         --disable-epsv  Inhibit using EPSV (F)

    而我们从Developer Tools返回的数据已经知道,返回数据的格式是

    “application/x-www-form-urlencoded”,所以很明显需要使用-d的HTTP POST data url encoded特性。不过格式中还有关键字form,莫非也支持-F参数登录,试试:

    curl -i --compressed http://172.22.54.31:8888/cloud/index.php?r=site/login -F “username=admin” -F “userpass=admin”,果然成功,呵呵~

    也许有同学有疑问,为何不模拟warnsetup、refer,这是因为测试时发现登录界面只需要用户名和密码就够了,refer 用于记录来源网页,在这里用处不大,warnsetup只是用于验证登录码的,这个已经去掉了。

    接下来要验证数据,我们在命令提示符中运行上面的命令,返回结果如下:

    HTTP/1.1 302 Moved Temporarily
    Date: Fri, 24 Aug 2012 08:29:07 GMT
    Content-Type: text/html
    Transfer-Encoding: chunked
    Connection: keep-alive
    X-Powered-By: PHP/5.4.3
    Set-Cookie: PHPSESSID=4711d2365de9aaaca0c28b1ca52183f0; path=/
    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Pragma: no-cache
    Set-Cookie: PHPSESSID=81d4bb65e888c1b6347120641eb4798b; path=/
    Location: ./index.php
    Server: 360 web server

    很奇怪吧,乍一看控制台没有返回任何有用信息,不过里面那句HTTP/1.1 302 Moved Temporarily是不是特别眼熟?这个特殊的302(表示http重定向)正是我们在Developer Tools看到的状态值,看到这个已经可以80%确定我们登录已经成功了,更重要的是返回包中的内容:Location: ./index.php,这说明控制台已经通知请求端跳转到index.php,如果登录失败控制台会继续停留在当前登录界面的,我们只需要修改curl语句中的用户名或者密码就知道了,这种情况下返回包就是登录界面的php源码,这里不再赘述。

    使用cURL以get方式测试控制台搜索接口

    测试方法同上面差不多,首先使用chrome打开控制台进入对应页面,在搜索框中输入“test.exe”,点击搜索,使用developer tools抓包,内容如下:

    cURL模拟get方式发送数据的参数是-G,了解这个后面要模拟就很简单了:

    curl -i --compressed -G “http://172.22.54.31:8888/cloud/index.php?r=file_cloud/api/search&filename=59c7dd2eafdbe86b2e23bcdabb575448&bg=0&lm=19 

    其中每个参数的含义要分别了解:filename表示输入的关键字,bg表示数据库第一行,lm表示共显示19行数据。这个接口返回的数据如下:

    {"rows":[{"level":"10","plevel":"10","id":"20","md5":"59c7dd2eafdbe86b2e23bcdabb575448","soft_name":"","soft_desc":"","file_desc":"QVBJIFRyYWNpbmcgWDg2IEhvb2sgRW5naW5l","is_sys_file":"127","size":"41984","is_rep":"0","file_name":"apihex86.d

    ll","file_version":"6.1.7600.16385","product_version":"6.1.7600.16385","copyright":"u00a9 Microsoft Corporation. All rights reserved.","lang":"0","org_name":"YXBpaGV4ODYuZGxs","sign_name":"TWljcm9zb2Z0IFdpbmRvd3M=","company_name":"Microsof

    t Corporation","update_time":"2012-07-31 18:14:27","create_time":"2012-07-31 18:14:27","creator_mid":"15be5b7dce003cdc2c1d1448afcf6cf0"}],"count":"1"}

    分别是文件属性和文件信息,这涉及到两个数据库表,所以验证数据需要用python从两张表中获取对应信息。

    从第一张表获取文件属性,比如只获取plevel:

    SELECT plevel FROM `file` where md5="59c7dd2eafdbe86b2e23bcdabb575448"

    从第二张表获取文件信息,比如只获取company_name:

    SELECT company_name FROM file_info where md5="59c7dd2eafdbe86b2e23bcdabb575448"

    Python代码如下:

    conn = MySQLdb.connect(host='%s'% self.host, user='user',passwd='test321',db='cloud')
     
    cursor = conn.cursor()
     
    count = cursor.execute('SELECT plevel FROM `file` where md5="111111932490c813bf5ea9d8aa6fa60c"')
     
    result = cursor.fetchone()      
     
    self.assertNotEqual(response.find(str(result[0])),-1)      
     
    count = cursor.execute('SELECT company_name FROM file_info where md5="111111932490c813bf5ea9d8aa6fa60c"')
     
    result1 = cursor.fetchone()      
     
    self.assertNotEqual(response.find(result1[0]),-1)

      当然严谨的测试案例是每一个属性字段都需要进行查找和匹配,这里就不再赘述了。

      后记:这种接口测试用到的无非就是curl、python的unitest而已,可能有的人会疑问,为什么用curl而不用py自带的pycurl或者request之类,我觉得只要能满足需求,能够用现成的就用成的,怎么简单怎么来。搞一堆代码维护起来也麻烦啊,现在qa行业跳槽也比较频繁,万一换了个人看不懂你的代码怎么办?呵呵

  • 相关阅读:
    GNU make manual 翻译(九十九)
    GNU make manual 翻译( 九十五)
    Shell的 for 循环小例子
    makefile中对目录遍历的小例子
    GNU make manual 翻译(九十三)
    GNU make manual 翻译( 一百)
    GNU make manual 翻译( 九十七)
    GNU make manual 翻译( 九十八)
    mapserver4.8.3 的readme.win32的中文翻译文件
    遥控器编程
  • 原文地址:https://www.cnblogs.com/dancesir/p/7573344.html
Copyright © 2011-2022 走看看