文章目录
- 一、前言
- 二、数据库
- 什么是数据验证
- 为什么需要操作数据库做数据验证?
- 现在回到怎样做数据验证的问题上来
- 三、[PyMSQL](https://pypi.org/project/pymssql/)
- pymysql如何操作数据库
- 实际应用
- 四、总结
一、前言
说起数据库的操作,咱们应该保持一颗敬畏的心,在很多时候,错误不一定是程序引起的,有可能是非法操作了数据库导致的,不到必要一般不建议直接去操作数据库,因为一旦操作错了,结果是不可逆的。那么先说说什么理由,非得要操作数据库?前面不是说了关于手机号的唯一性?接口测试数据库断言?还有批量构造数据?NoNoNo,这不能算作理由,但可以进行风险评估,如果动作较大,建议出具必要的方案:如何动,怎么动,坏了怎么办?预案?如何恢复?等等这些步骤一个也不少的准备清楚,避免给公司正常运营造成经济损失。
二、数据库
这里不介绍如何操作数据库,而是说通过写python代码去操作数据库。sql语法是基础,而PyMySQL是需要掌握的;当然这里以MySQL数据库为例。
什么是数据验证
对于影响数据库表结构的接口,在测试的时候除了要验证接口的响应数据,还需要验证表数据的正确性,
通过计算对比都没问题了才认为测试通过,那么从请求到获取数据、再去检查数据的过程就是接口数据验证。
为什么需要操作数据库做数据验证?
例举操作数据库做数据验证的使用场景。
- 接口测试,数据库结果断言?
请求接口返回数据,结果断言,需要拿到接口返回的数据去和数据库的数据进行比较?Excuse me,接口返回的数据不就是从数据库里面来的吗?为什么还需要自己去写sql,然后将查询的结果与接口返回的结果进行比较?
首先说一下接口的本质,它是函数,那么它的底层不就是对数据库的操作?以上做法,你是在质疑开发写的sql有毛病?有这个想法没毛病,开发写的任何东西都需要经得起测试。
好,假设没毛病!但对于另一类场景,例如用户账户余额,先查出余额,然后再支付使用了余额,最后查询账户还剩余多少,这个是可以的。因为前面的结果是测试用例计算的,而不是接口,接口也不见得一定会返回余额(因为前端也会计算,虽然不一定会这样做);除此之外,不管是充值还是支付,都会产生一条流水,对于账户余额的变动都可以做数据验证,流水也可以去校验,是否产生了流水、流水的金额是否与请求接口的数据一致、余额变动是否正确等等。
现在回到怎样做数据验证的问题上来
经过对上面问题的分析:不建议所有接口都做数据验证(程序代码任何操作都会给资源造成开销,数据库层面的操作过多,会给框架的执行效率带来麻烦,并且对数据库操作也有一定的风险),对于需要做数据验证的接口,咱们需要了解整个业务场景,前后可能变化的数据,数据库会产生怎样的业务数据,并准备对应的sql脚本即可;那么剩下的是框架设计。
三、PyMSQL
安装工具库:pip install pymssql
- 先看网站案例⬇⬇⬇
conn = pymssql.connect(server, user, password, "tempdb")
cursor = conn.cursor(as_dict=True)cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in cursor:print("ID=%d, Name=%s" % (row['id'], row['name']))conn.close()
这感觉,是不是简单粗暴多了;几行代码就完成了数据的访问和读取数据。
pymysql如何操作数据库
还记得之前的举例吗:如何将大象装进冰箱?
- 第一步:创建数据库连接对象;服务器地址、帐号密码、数据库、端口等参数;
- 第二步:拿到连接对象并获取游标,这里需要明白游标的概念:
科普:游标(cursor)是一个存储在mysql服务器上的数据库查询,它不是一条SELECT语句,而是被SELECT语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。
- 第三步:操作sql语句,对于select语句而言没有commit也没有rollback,只有fetchone一条还是fetchall多条;
- 第四步:先关闭游标(其实在执行完sql就需要关闭游标),再最后再关闭连接对象。
class HandleMySQL:"""通过ssh隧道连接内网阿里云数据库操作"""def __init__(self, mysql_host, mysql_db, mysql_account, mysql_passwd, mysql_port=3306):"""构造函数,初始化类属性,有些默认值"""# 与跳板机同局域网的内网访问地址self.mysql_accout = mysql_accountself.mysql_passwd = mysql_passwdself.mysql_host = mysql_hostself.mysql_port = mysql_portself.mysql_db = mysql_dbtry:# 创建数据连接对象self.con = pymysql.connect(host=self.mysql_host,port=self.mysql_port,user=self.mysql_accout,password=self.mysql_passwd,db=self.mysql_db,charset='utf8')except:logger.error("Database connection failed!")else:self.cur = self.con.cursor(cursor=pymysql.cursors.DictCursor)logger.info("Database connection successful!")def selectDB(self, sql):"""select数据库操作"""try:self.cur.execute(sql)datas = self.cur.fetchone()except:logger.error("Error: unable to fecth data")finally:self.cur.close()return datasdef usuallyDB(self, sql):r"""insert\update\delete数据库操作"""try:self.cur.execute(sql)self.con.commit()except:self.con.rollback()finally:self.cur.close()def closeDB(self):"""关闭数据库连接"""# self.cur.close() 在执行的时候已经关闭了游标self.con.close()
实际应用
前面讲了python如何使用pymysql操作mysql数据库;但是在接口自动化测试框架中如何设计使用呢?
- 接口用例设计,在用例模版中预留两列,前后处理sql脚本,其他形式用例模版也可参考;
- 那sql脚本应该在测试用例中如何使用呢?
思考一下,咱们读取excel的用例作为数据源驱动测试用例的时候,是不是需要获取每一列,如果有数据的话,没有则单元格返回None;
# 是不是应该写在测试方法中,不建议是在setup/teardown这类前后置方法中(其实在excel用例也用不到这里去)
#
# 但是可以在setUpClass中创建mysql的连接对象,tearDownClass中关闭连接;
#
# 获取测试用例参数列
#
if pre_sql:r = pyConn.excute(sql)setattr(TestData,"id",r)
#
# 发送http请求并提取响应结果等操作
#
if post_sql:r = pyConn.excute(sql)setattr(TestData,"account",r)
#
# 写其他逻辑:如断言
#
self.assertEquels(r,actual,"断言成功")
- 格式呢,差不多就这个意思,如果有什么不同的地方,这考量的就是各位对自家的业务流程熟练程度了。
四、总结
这应该是《接口自动化测试框架》,本框架中最后一个讲如何操作一个事物的内容了,不知大家有没有发现,不管是读配置文件、还是读取excel测试用例;它的步骤都是有迹可循的,先怎样(读取指定文件/连接服务器),再怎样(读取/操作数据),最后再怎样(一般都需要关闭资源/销毁对象),即使是一个完全陌生的功能库,咱们也应该能从源码中找到对应的API来写操作方法;如此一想,确实如此!!!