• 简单实现接口自动化测试(基于python+unittest)


    简介

    本文通过从Postman获取基本的接口测试Code简单的接口测试入手,一步步调整优化接口调用,以及增加基本的结果判断,讲解Python自带的Unittest框架调用,期望各位可以通过本文对接口自动化测试有一个大致的了解。

    引言

    为什么要做接口自动化测试?

    在当前互联网产品迭代频繁的背景下,回归测试的时间越来越少,很难在每个迭代都对所有功能做完整回归。但接口自动化测试因其实现简单、维护成本低,容易提高覆盖率等特点,越来越受重视。

    为什么要自己写框架呢?

    使用Postman调试通过过直接可以获取接口测试的基本代码,结合使用requets + unittest很容易实现接口自动化测试的封装,而且requests的api已经非常人性化,非常简单,但通过封装以后(特别是针对公司内特定接口),可以进一步提高脚本编写效率。

    一个现有的简单接口例子

    下面使用requests + unittest测试一个查询接口

    接口信息如下

    请求信息:

    Method:POST

    URL:api/match/image/getjson

    Request:

    1. {
    2. "category": "image",
    3. "offset": "0",
    4. "limit": "30",
    5. "sourceId": "0",
    6. "metaTitle": "",
    7. "metaId": "0",
    8. "classify": "unclassify",
    9. "startTime": "",
    10. "endTime": "",
    11. "createStart": "",
    12. "createEnd": "",
    13. "sourceType": "",
    14. "isTracking": "true",
    15. "metaGroup": "",
    16. "companyId": "0",
    17. "lastDays": "1",
    18. "author": ""
    19. }

    Response示例:

    1. {
    2. "timestamp" : xxx,
    3. "errorMsg" : "",
    4. "data" : {
    5. "config" : xxx
    6. }

    Postman测试方法见

    测试思路

    1.获取Postman原始脚本

    2.使用requests库模拟发送HTTP请求**

    3.对原始脚本进行基础改造**

    4.使用python标准库里unittest写测试case**

    原始脚本实现

    未优化

    该代码只是简单的一次调用,而且返回的结果太多,很多返回信息暂时没用,示例代码如下

    1. import requests
    2. url = "http://cpright.xinhua-news.cn/api/match/image/getjson"
    3. querystring = {"category":"image","offset":"0","limit":"30","sourceId":"0","metaTitle":"","metaId":"0","classify":"unclassify","startTime":"","endTime":"","createStart":"","createEnd":"","sourceType":"","isTracking":"true","metaGroup":"","companyId":"0","lastDays":"1","author":""}
    4. headers = {
    5. 'cache-control': "no-cache",
    6. 'postman-token': "e97a99b0-424b-b2a5-7602-22cd50223c15"
    7. }
    8. response = requests.request("POST", url, headers=headers, params=querystring)
    9. print(response.text)
    优化 第一版

    调整代码结构,输出结果Json出来,获取需要验证的response.status_code,以及获取结果校验需要用到的results['total']

    1. #!/usr/bin/env python
    2. #coding: utf-8
    3. '''
    4. unittest merchant backgroud interface
    5. @author: zhang_jin
    6. @version: 1.0
    7. @see:http://www.python-requests.org/en/master/
    8. '''
    9. import unittest
    10. import json
    11. import traceback
    12. import requests
    13. url = "http://cpright.xinhua-news.cn/api/match/image/getjson"
    14. querystring = {
    15. "category": "image",
    16. "offset": "0",
    17. "limit": "30",
    18. "sourceId": "0",
    19. "metaTitle": "",
    20. "metaId": "0",
    21. "classify": "unclassify",
    22. "startTime": "",
    23. "endTime": "",
    24. "createStart": "",
    25. "createEnd": "",
    26. "sourceType": "",
    27. "isTracking": "true",
    28. "metaGroup": "",
    29. "companyId": "0",
    30. "lastDays": "1",
    31. "author": ""
    32. }
    33. headers = {
    34. 'cache-control': "no-cache",
    35. 'postman-token': "e97a99b0-424b-b2a5-7602-22cd50223c15"
    36. }
    37. #Post接口调用
    38. response = requests.request("POST", url, headers=headers, params=querystring)
    39. #对返回结果进行转义成json串
    40. results = json.loads(response.text)
    41. #获取http请求的status_code
    42. print "Http code:",response.status_code
    43. #获取结果中的total的值
    44. print results['total']
    45. #print(response.text)
    优化 第二版

    接口调用异常处理,增加try,except处理,对于返回response.status_code,返回200进行结果比对,不是200数据异常信息。

    1. #!/usr/bin/env python
    2. #coding: utf-8
    3. '''
    4. unittest merchant backgroud interface
    5. @author: zhang_jin
    6. @version: 1.0
    7. @see:http://www.python-requests.org/en/master/
    8. '''
    9. import json
    10. import traceback
    11. import requests
    12. url = "http://cpright.xinhua-news.cn/api/match/image/getjson"
    13. querystring = {
    14. "category": "image",
    15. "offset": "0",
    16. "limit": "30",
    17. "sourceId": "0",
    18. "metaTitle": "",
    19. "metaId": "0",
    20. "classify": "unclassify",
    21. "startTime": "",
    22. "endTime": "",
    23. "createStart": "",
    24. "createEnd": "",
    25. "sourceType": "",
    26. "isTracking": "true",
    27. "metaGroup": "",
    28. "companyId": "0",
    29. "lastDays": "1",
    30. "author": ""
    31. }
    32. headers = {
    33. 'cache-control': "no-cache",
    34. 'postman-token': "e97a99b0-424b-b2a5-7602-22cd50223c15"
    35. }
    36. try:
    37. #Post接口调用
    38. response = requests.request("POST", url, headers=headers, params=querystring)
    39. #对http返回值进行判断,对于200做基本校验
    40. if response.status_code == 200:
    41. results = json.loads(response.text)
    42. if results['total'] == 191:
    43. print "Success"
    44. else:
    45. print "Fail"
    46. print results['total']
    47. else:
    48. #对于http返回非200code,输出相应的code
    49. raise Exception("http error info:%s" %response.status_code)
    50. except:
    51. traceback.print_exc()
    优化 第三版

    1.该版本改动较大,引入config文件,单独封装结果校验模块,引入unittest模块,实现接口自动调用,并增加log处理模块;
    2.对不同Post请求结果进行封装,不同接口分开调用;
    3.测试用例的结果进行统计并最终输出

    1. #!/usr/bin/env python
    2. #coding: utf-8
    3. '''
    4. unittest interface
    5. @author: zhang_jin
    6. @version: 1.0
    7. @see:http://www.python-requests.org/en/master/
    8. '''
    9. import unittest
    10. import json
    11. import traceback
    12. import requests
    13. import time
    14. import result_statistics
    15. import config as cf
    16. from com_logger import match_Logger
    17. class MyTestSuite(unittest.TestCase):
    18. """docstring for MyTestSuite"""
    19. #@classmethod
    20. def sedUp(self):
    21. print "start..."
    22. #图片匹配统计
    23. def test_image_match_001(self):
    24. url = cf.URL1
    25. querystring = {
    26. "category": "image",
    27. "offset": "0",
    28. "limit": "30",
    29. "sourceId": "0",
    30. "metaTitle": "",
    31. "metaId": "0",
    32. "classify": "unclassify",
    33. "startTime": "",
    34. "endTime": "",
    35. "createStart": "",
    36. "createEnd": "",
    37. "sourceType": "",
    38. "isTracking": "true",
    39. "metaGroup": "",
    40. "companyId": "0",
    41. "lastDays": "1",
    42. "author": ""
    43. }
    44. headers = {
    45. 'cache-control': "no-cache",
    46. 'postman-token': "545a2e40-b120-2096-960c-54875be347be"
    47. }
    48. response = requests.request("POST", url, headers=headers, params=querystring)
    49. if response.status_code == 200:
    50. response.encoding = response.apparent_encoding
    51. results = json.loads(response.text)
    52. #预期结果与实际结果校验,调用result_statistics模块
    53. result_statistics.test_result(results,196)
    54. else:
    55. print "http error info:%s" %response.status_code
    56. #match_Logger.info("start image_query22222")
    57. #self.assertEqual(results['total'], 888)
    58. '''
    59. try:
    60. self.assertEqual(results['total'], 888)
    61. except:
    62. match_Logger.error(traceback.format_exc())
    63. #print results['total']
    64. '''
    65. #文字匹配数据统计
    66. def test_text_match_001(self):
    67. text_url = cf.URL2
    68. querystring = {
    69. "category": "text",
    70. "offset": "0",
    71. "limit": "30",
    72. "sourceId": "0",
    73. "metaTitle": "",
    74. "metaId": "0",
    75. "startTime": "2017-04-14",
    76. "endTime": "2017-04-15",
    77. "createStart": "",
    78. "createEnd": "",
    79. "sourceType": "",
    80. "isTracking": "true",
    81. "metaGroup": "",
    82. "companyId": "0",
    83. "lastDays": "0",
    84. "author": "",
    85. "content": ""
    86. }
    87. headers = {
    88. 'cache-control': "no-cache",
    89. 'postman-token': "ef3c29d8-1c88-062a-76d9-f2fbebf2536c"
    90. }
    91. response = requests.request("POST", text_url, headers=headers, params=querystring)
    92. if response.status_code == 200:
    93. response.encoding = response.apparent_encoding
    94. results = json.loads(response.text)
    95. #预期结果与实际结果校验,调用result_statistics模块
    96. result_statistics.test_result(results,190)
    97. else:
    98. print "http error info:%s" %response.status_code
    99. #print(response.text)
    100. def tearDown(self):
    101. pass
    102. if __name__ == '__main__':
    103. #image_match_Logger = ALogger('image_match', log_level='INFO')
    104. #构造测试集合
    105. suite=unittest.TestSuite()
    106. suite.addTest(MyTestSuite("test_image_match_001"))
    107. suite.addTest(MyTestSuite("test_text_match_001"))
    108. #执行测试
    109. runner = unittest.TextTestRunner()
    110. runner.run(suite)
    111. print "success case:",result_statistics.num_success
    112. print "fail case:",result_statistics.num_fail
    113. #unittest.main()
    最终输出日志信息
    1. Zj-Mac:unittest lazybone$ python image_test_3.py
    2. 测试结果:通过
    3. .测试结果:不通过
    4. 错误信息: 期望返回值:190 实际返回值:4522
    5. .
    6. ----------------------------------------------------------------------
    7. Ran 2 tests in 0.889s
    8. OK
    9. success case: 1
    10. fail case: 1

    后续改进建议

    1.unittest输出报告也可以推荐使用HTMLTestRunner(我目前是对结果统计进行了封装)

    2.接口的继续封装,参数化,模块化

    3.unittest单元测试框架实现参数化调用第三方模块引用(nose-parameterized)

    4.持续集成运行环境、定时任务、触发运行、邮件发送等一系列功能均可以在Jenkins上实现。

  • 相关阅读:
    CLIP-LITE造假
    使用分类权重解决数据不平衡的问题
    TUN设备和TAP设备
    排序算法的奥秘:JAVA中的揭秘与实现
    微信小程序结合php后台实现登录授权机制详解
    无分类器指导的Classifier-free Diffusion Models技术
    【2023最新版】MySQL安装教程
    微信小程序开发---基本组件的使用
    Spark基本知识
    基于Android的电子书阅读器的设计与实现
  • 原文地址:https://blog.csdn.net/jj2772367224/article/details/133715795