接口测试 关于设计接口自动化测试的看法

虫师 · 2016年12月02日 · 最后由 mg 回复于 2018年07月11日 · 3565 次阅读

第一次发言,其实也不是真的第一次,去年问过一个 appium 的问题,管理员认为我姿势不对,没审核过。这次再试试吧!
逛了半天的接口测试相关的帖子,在自动化测试框架的设计上,“个人” 感觉大家的思路不太对。感觉把简单的问题复杂化了。

我认为接口测试在测试的几个方面是最简单的:
拿 postman 来说,粘贴个 url,加个参数,选择 GET/POST,点一个按钮数据返回。
人工对比一下接口数据对不对就 OK 了----> 还有比这更简单的测试? 功能测试、单元测试、性能测试都比这儿难多了。

这么简单的测试,大家的在设计单元测试框架的思路是什么?怎样不写接口测试代码!嗯,大家都在用写代码的方式解决怎样避免写代码。

  • 有同学提出接口能不能录制啊? ---这是什么奇葩需求。
  • 有同学问能不能在 WEB 页面配置接口,测试接口啊?(Swagger)
  • 有同学说接口数据我得抽离出来单独描述?(pyresttest)

以前大多测试不会写代码,大家说:测试不会写代码没逼格。现在大多测试都会写代码了,又说:做自动化测试要只写代码没逼格?
一定要做封装,用 UI/配置文件来填写接口测试。----->这不就是在走接口工具的路么?

为什么要把简单的问题复杂化呢?只写代码就维护成本高?写做成 UI,或用各种接口配置文件,接口描述文件来写接口用例就维护成本低?

那么接口自动化的目的是什么? 主要就是解决接口工具的不足嘛。

一般接口工具有什么不足:

  • 1、测试数据初始化。有一个用户查询的接口,我传了 name="zhangsan",首先数据库得有一条 zhangsan 的个人信息,接口才能返回 zhangsan 的数据,对吧?想想怎么在跑接口用例时,先初始化测试数据。
  • 2、加密接口。接口工具碰到各种加密算法、时间戳的接口一准傻眼。
  • 3、不够自动化。用例的断言、批理执行、生成测试报告、集成 CI,自动发邮件。(有些工具也部分支持)

我觉得只要能解决以上三点不足,就是一个好的接口自动化测试框。其它各种玩法都是不必要。

我的使用的是 Python + unittest + HTMLTestRunner + requests + pymysql

  • pymysql MySQL 驱动,操作 MySQL 数据库,初始化测试数据。如果你的项目是其它数据库,请用其它驱动。
  • unittest 是来解决用例的组织与执行
  • HTMLTestRunner 基于 unittest 单元测试框的扩展,生成 HTML 测试报告,可以自己定制。
  • requests 发送 HTTP 接口的库

帖一个加密接口的例子。

#coding=utf-8
import requests
import unittest
import json
import hashlib
import time
from ReportTestRunner import HTMLTestRunner


class edmMailSystemTest(unittest.TestCase):

    def setUp(self):
        self.base_url = "http://aaa.xxxx.com/mail/send"
        self.now_time = int(time.time())

    def md5_str(self,now_time):
        # $app_key.$time.$app_ secret.'&edm-xxx'  --->加密接口的处理
        app_key = 'kkkk'
        time_ = str(now_time)
        app_secret = 'adfasdfasdf'
        md5 = hashlib.md5()
        md5.update(app_key + time_ + app_secret + '&edm-xxx')
        md5_ = md5.hexdigest()
        return md5_

    def test_all_parameter_null(self):
        u'''测试不传任何参数'''
        r = requests.post(self.base_url)
        code = r.status_code
        dicts = json.loads(r.text)
        print(dicts)
        self.assertEqual(code,200)
        self.assertEqual(dicts['status'],10021)
        self.assertEqual(dicts['message'],'Parameters  error!')

    def test_all_parameter_incomplete(self):
        u'''测试参数不完整'''
        payload = {'subject':'send mail test','html':'hello, xiaoming.',}
        r = requests.post(self.base_url,data=payload)
        code = r.status_code
        dicts = json.loads(r.text)
        print(dicts)
        self.assertEqual(code,200)
        self.assertEqual(dicts['status'],10021)
        self.assertEqual(dicts['message'],'Parameters  error!')

    def test_app_null(self):
        u'''这个程序不存在'''
        now_time = str(self.now_time)
        sign = self.md5_str(self.now_time)
        payload = {'subject':'send mail test',
                   'html':'hello, xiaoming.',
                   'app_key':'kkkk_app_null',  
                   'time':now_time,
                   'sign':sign,
                   'to':'zhangsan@aaaa.com'}
        r = requests.post(self.base_url,data=payload)
        code = r.status_code
        dicts = json.loads(r.text)
        print(dicts)
        self.assertEqual(code,200)
        self.assertEqual(dicts['status'],10022)
        self.assertEqual(dicts['message'],'The app is not Exist!')

    def test_timeout(self):
        u'''时间过期'''
        now_time = str(self.now_time-61)
        sign = self.md5_str(self.now_time)
        payload = {'subject':'send mail test',
                   'html':'hello, xiaoming.',
                   'app_key':'kkkk',
                   'time':now_time,
                   'sign':sign,
                   'to':'zhangsan@aaaa.com'}
        r = requests.post(self.base_url,data=payload)
        code = r.status_code
        dicts = json.loads(r.text)
        print(dicts)
        self.assertEqual(code,200)
        self.assertEqual(dicts['status'],10027)
        self.assertEqual(dicts['message'],'The time is  expire!')

    def test_sign_error(self):
        u'''签名错误'''
        now_time = str(self.now_time)
        sign = self.md5_str(self.now_time)
        payload = {'subject':'send mail test',
                   'html':'hello, xiaoming.',
                   'app_key':'kkkk',  
                   'time':now_time,
                   'sign':sign+'aaaa',
                   'to':'zhangsan@aaaa.com'}
        r = requests.post(self.base_url,data=payload)
        code = r.status_code
        dicts = json.loads(r.text)
        print(dicts)
        self.assertEqual(code,200)
        self.assertEqual(dicts['status'],10028)
        self.assertEqual(dicts['message'],'The sign is not match!')

……


加密接口,直接写代码是最灵活的了。生成 md5,取时间戳都很方便。干嘛非要封装成 UI 必然会损失这种便捷性。步接口工具的后尘。

喜欢玩工具的同学绕道~~!

测试报告

完整项目,请看我的 github:
https://github.com/defnngj/pyrequest

共收到 11 条回复 时间 点赞

虫师发话啦,讲的还是有一定道理,其实我倒是这么看待的,不分对错,思维不局限,百花齐放才是更好的
ps:俺找你买过 java 版 selenium

—— 来自 TesterHome 官方 安卓客户端

虫师 #10 · 2016年12月02日 Author

#1 楼 @hu_qingen 噢! 今年一直在接口自动化方法面的研究和总结。马上有本相关的书要出版了。 我来这里逛逛。

#2 楼 @fnngj 挺同意你的想法的。 我专门写过数据管理的帖子,讲的是在自动化测试中怎么管理测试数据的。其中包含了数据的创建和销毁。我感觉数据是自动化测试的关键? 我个人也是不太喜欢录制回放和关键字驱动框架。不灵活,不可应变。 UI 复杂点,case 多一点。这些框架就报废了。 写代码可以依赖比较好的设计避免这些问题。

赞同这个。我现在也没有做关键词驱动方面的框架,觉得性价比不高。主要是测试人员只有我一个(手动再见)

马克,学习一下思路

前期阶段,重点在于接口单测,后期阶段,侧重点在于接口的场景化测试,各阶段的着重点不同

@fnngj python 做底层去解决 java 类的工程很难的,加密类的自定义算法,或者内部服务是没法解决的😂

unittest 支持多线程吗?
case 数量几百上千后,执行时间就会变长。

这个思路不错,具体需求还是看具体业务,个人感觉接口测试行业里搞定有点复杂啦

Michael_Wang 回复

用多进程会好点

你好 如果 Excel 表里面的接口 涉及到传值依赖性的问题 即 第二个接口有两个传值是第一个接口的返回值中的某两个 这个时候怎么处理呀 两个参数在 Excel 表里面 用分号隔开吗
感谢

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册