接口自动化学习(3)

1.json和字典dict的区别?

现在自动化培训烂大街,是个人都能说的上几个框架,面试如果问框架相关问题,求职者只需一瓶82年的雪碧,会吹的让你怀疑人生!
所以面试官为了更清楚的知道你是停留在表面上的花拳绣腿还是有扎实的基础,就不会问框架这种东西了。基本上问几个数据类型的基础就知道有没货了。

那么json和字典到底有什么区别呢?初学者连python的基础数据类型都没搞清楚,直接撸框架,有的人学了几个月可能都迷迷糊糊的,以为json就是字典。这个是肯定不对的。

首先python里面的基础数据类型有:int、str、 float、list、bool、tuple、dict、set这几种类型,里面没json这种数据类型。

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

由于你的代码是python写的(也有可能是php, java,c,ruby等语言),但是后端接口是java写的(也有可能是其它语言),不同的语言数据类型是不一样的(就好比中国的语言和美国的语言数据类型也不一样,中国的一般说一只羊,一头牛,美国都是 a /an这种单位),所以就导致你提交的数据,别的开发语言无法识别,这就需要规范传输的数据(传输的数据都是一个字符串),大家都遵循一个规范,按一个标准的格式去传输,于是就有就json这种国际化规范的数据类型。

json本质上还是字符串,只是按key:value这种键值对的格式来的字符串

 

import json
 
# a是字典dict
a = {"a": 1, "b": 2, "c": True}
 
# b是json
b = '{"a": 1, "b": 2, "c": true}'
 
print(type(a))
print(json.dumps(a))   # a转json

  

运行结果

<class 'dict'>
{"a": 1, "b": 2, "c": true}
<class 'str'>
{'a': 1, 'b': 2, 'c': True}

  

Python开发中字典和 json的概念区别:


  一、字典


  字典是一种数据结构,而json是一种数据格式,格式就会有一些形式上的限制,比如json的格式要求必须且只能使用双引号作为key或者值的边界符号(值如果是数字可以不用加双引号),不能使用单引号,用单引号或者不用引号会导致读取数据错误,而且“key”必须使用边界符(双引号),但字典就无所谓了,可以使用单引号,也可以使用双引号。


  dict是一个完整的数据结构,是对Hash Table这一数据结构的一种实现,是一套从存储到提取都封装好了的方案。它使用内置的哈希函数来规划key对应value的存储位置,从而获得O(1)的数据读取速度。


  二、json


  json是JavaScript Object Notation的首字母缩写,字面的意思是javascript对象表示法,这里说的json指的是类似于javascript对象的一种数据格式对象,目前这种数据格式比较流行,逐渐替换掉了传统的xml数据格式, 前端使用ajax的时候后台返回该前端的数据格式就是json格式的。


  json是一种数据格式,是纯字符串。可以被解析成Python的dict或者其他形式。


  三、json和dict区别对比


  json的key只能是字符串,python的dict可以是任何可hash对象(hashtable type);


  json的key可以是有序、重复的;dict的key不可以重复。


  json的value只能是字符串、浮点数、布尔值或者null,或者它们构成的数组或者对象。


  json任意key存在默认值undefined,dict默认没有默认值;


  json访问方式可以是[],也可以是.,遍历方式分in、of;dict的value仅可以下标访问。


  json的字符串强制双引号,dict字符串可以单引号、双引号;


  dict可以嵌套tuple,json里只有数组。


  json:true、false、null


  python:True、False、None


  json中文必须是unicode编码,如"\u6211".


  json的类型是字符串,字典的类型是字典。


  四、hashtable


  一个对象当其声明周期内的hash值不发生改变,而且可以跟其他对象进行比较时,这个对象就是hashtable的。


  1、python中的基本类型都是Hashtable,如str、bytes、数字类型、tuple等;


  2、用户自定义的类型默认都是hashtable,因为它们的hash值就是id()值;


  3、frozenset始终都是hashtable的,因为它们所有的项目都是被定义成hashtable的;


  4、只有当tuple内的所有项都是hashtable的时候,tuple才是hashtable;

2.测试的数据你放在哪?

测试数据到底该怎么放,这个是面试官最喜欢问的一个题了,似乎仁者见仁智者见智,没有标准的答案,有的人说放excel,也有的说放.py脚本,也有的说放ini配置文件,
还有放到json,yaml文件,txt文件,甚至有的放数据库,五花八门,一百个做自动化的小伙伴有100个放的地方。

这里总结下测试的数据到底该怎么放?

首先测试的数据是分很多种的,有登录的账户数据,也有注册的账户数据,还有接口的参数,还有邮箱配置的数据等等等等,所以这个题不能一概而论给答死了。要不然就是给自己挖坑。

以下两个大忌不能回答:

  • 测试的数据是不能写死到代码里面的,这个是原则问题,也是写代码的大忌(你要是回答写在代码里面,估计就是回去等通知了)
  • 测试数据放到.py的开头,这种其实很方便,对于少量的,固定不变的数据其实是可以放的,但是面试时候,千万不能这样说,面试官喜欢装逼的方法

测试数据存放总结:

1.对于账号密码,这种管全局的参数,可以用命令行参数,单独抽出来,写的配置文件里(如ini)
2.对于一些一次性消耗的数据,比如注册,每次注册不一样的数,可以用随机函数生成
3.对于一个接口有多组测试的参数,可以参数化,数据放yaml,text,json,excel都可以
4.对于可以反复使用的数据,比如订单的各种状态需要造数据的情况,可以放到数据库,每次数据初始化,用完后再清理
5.对于邮箱配置的一些参数,可以用ini配置文件
6.对于全部是独立的接口项目,可以用数据驱动方式,用excel/csv管理测试的接口数据
7.对于少量的静态数据,比如一个接口的测试数据,也就2-3组,可以写到py脚本的开头,十年八年都不会变更的

总之不同的测试数据,可以用不同的文件管理

3.什么是数据驱动,如何参数化?

参数化和数据驱动的概念这个肯定要知道的,参数化的思想是代码用例写好了后,不需要改代码,只需维护测试数据就可以了,并且根据不同的测试数据生成多个用例
python里面用unittest框架

import unittest
import ddt
 
# 测试数据
datas = [ {"user": "admin", "psw": "123", "result": "true"},
        {"user": "admin1", "psw": "1234", "result": "true"},
        {"user": "admin2", "psw": "1234", "result": "true"},
        {"user": "admin3", "psw": "1234", "result": "true"},
        {"user": "admin4", "psw": "1234", "result": "true"},
        {"user": "admin5", "psw": "1234", "result": "true"},
        {"user": "admin6", "psw": "1234", "result": "true"},
        {"user": "admin7", "psw": "1234", "result": "true"},
        {"user": "admin8", "psw": "1234", "result": "true"},
        {"user": "admin9", "psw": "1234", "result": "true"},
        {"user": "admin10", "psw": "1234", "result": "true"},
        {"user": "admin11", "psw": "1234", "result": "true"}]
 
@ddt.ddt
class Test(unittest.TestCase):
 
    @ddt.data(*datas)
    def test_(self, d):
        """上海-悠悠:{0}"""
        print("测试数据:%s" % d)
 
if __name__ == "__main__":
    unittest.main()

  

unittest框架还有一个paramunittest也可以实现

import unittest
import paramunittest
import time
# python3.6
# 作者:上海-悠悠
 
@paramunittest.parametrized(
    {"user": "admin", "psw": "123", "result": "true"},
    {"user": "admin1", "psw": "1234", "result": "true"},
    {"user": "admin2", "psw": "1234", "result": "true"},
    {"user": "admin3", "psw": "1234", "result": "true"},
    {"user": "admin4", "psw": "1234", "result": "true"},
    {"user": "admin5", "psw": "1234", "result": "true"},
    {"user": "admin6", "psw": "1234", "result": "true"},
    {"user": "admin7", "psw": "1234", "result": "true"},
    {"user": "admin8", "psw": "1234", "result": "true"},
    {"user": "admin9", "psw": "1234", "result": "true"},
    {"user": "admin10", "psw": "1234", "result": "true"},
    {"user": "admin11", "psw": "1234", "result": "true"},
)
 
class TestDemo(unittest.TestCase):
    def setParameters(self, user, psw, result):
        '''这里注意了,user, psw, result三个参数和前面定义的字典一一对应'''
        self.user = user
        self.user = psw
        self.result = result
 
    def testcase(self):
        print("开始执行用例:--------------")
        time.sleep(0.5)
        print("输入用户名:%s" % self.user)
        print("输入密码:%s" % self.user)
        print("期望结果:%s " % self.result)
        time.sleep(0.5)
        self.assertTrue(self.result == "true")
 
 
if __name__ == "__main__":
    unittest.main(verbosity=2)

  

如果用的是pytest框架,也能实现参数化

# content of test_canshu1.py
 
# coding:utf-8
 
import pytest
@pytest.mark.parametrize("test_input,expected",
                         [ ("3+5", 8),
                           ("2+4", 6),
                           ("6 * 9", 42),
                         ])
def test_eval(test_input, expected):
    assert eval(test_input) == expected
 
if __name__ == "__main__":
    pytest.main(["-s", "test_canshu1.py"])

  

pytest里面还有一个更加强大的功能,获得多个参数化参数的所有组合,可以堆叠参数化装饰器

import pytest
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
    print("测试数据组合:x->%s, y->%s" % (x, y))
 
 
if __name__ == "__main__":
    pytest.main(["-s", "test_canshu1.py"])

  

4.下个接口请求参数依赖上个接口的返回数据

这个很容易,不同的接口封装成不同的函数或方法,需要的数据return出来,用一个中间变量a去接受,后面的接口传a就可以了
参考这篇【python接口自动化26-参数关联和JSESSIONID(上个接口返回数据作为下个接口请求参数)】

5.依赖于登录的接口如何处理

登录接口依赖token的,可以先登录后,token存到一个yaml或者json,或者ini的配置文件里面,后面所有的请求去拿这个数据就可以全局使用了
参考之前分享的一篇python接口自动化24-有token的接口项目使用unittest框架设计

如果是cookies的参数,可以用session自动关联

s=requests.session()

  

后面请求用s.get()和s.post()就可以自动关联cookies了

6.依赖第三方的接口如何处理

这个需要自己去搭建一个mock服务,模拟接口返回数据,参考【python笔记25-mock-server之moco】(https://www.cnblogs.com/yoyoketang/p/9348552.html)

moco是一个开源的框架,在github上可以下载到https://github.com/dreamhead/moco

moco服务搭建需要自己能够熟练掌握,面试会问你具体如何搭建 ,如何模拟返回的数据,是用的什么格式,如何请求的

7.不可逆的操作,如何处理,比如删除一个订单这种接口如何测试

此题考的是造数据的能力,接口的请求数据,很多都是需要依赖前面一个状态的
比如工作流这种,流向不同的人状态不一样,操作权限不一样,测试的时候,每种状态都要测到,就需要自己会造数据了。
平常手工测试造数据,直接在数据库改字段状态。那么自动化也是一样,造数据可以用python连数据库了,做增删改查的操作
测试用例前置操作,setUp做数据准备
后置操作,tearDown做数据清理

8.接口产生的垃圾数据如何清理

跟上面一样,造数据和数据清理,需用python连数据库了,做增删改查的操作
测试用例前置操作,setUp做数据准备
后置操作,tearDown做数据清理

9.一个订单的几种状态如何全部测到,如:未处理,处理中,处理失败,处理成功

跟上面一样,也是考察造数据,修改数据的状态

10.python如何连接数据库操作?

这个就是详细的考察你是如何用python连数据库的,并且最好能现场写代码那种(有的笔试题就是python连数据库)
具体问你用到哪个模块,查询的数据是什么类型?如何删除数据?如何新增数据?如何修改数据?
PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。
详情参考教程http://www.runoob.com/python3/python3-mysql.html

#!/usr/bin/python3
# 查询EMPLOYEE表中salary(工资)字段大于1000的所有数据:
import pymysql
 
# 打开数据库连接
db = pymysql.connect("localhost","testuser","test123","TESTDB" )
 
# 使用cursor()方法获取操作游标 
cursor = db.cursor()
 
# SQL 查询语句
sql = "SELECT * FROM EMPLOYEE \
       WHERE INCOME > %s" % (1000)
try:
   # 执行SQL语句
   cursor.execute(sql)
   # 获取所有记录列表
   results = cursor.fetchall()
   for row in results:
      fname = row[0]
      lname = row[1]
      age = row[2]
      sex = row[3]
      income = row[4]
       # 打印结果
      print ("fname=%s,lname=%s,age=%s,sex=%s,income=%s" % \
             (fname, lname, age, sex, income ))
except:
   print ("Error: unable to fetch data")
 
# 关闭数据库连接
db.close()

 

11、post请求的四种参数形式是什么

application/x-www-form-urlencoded 

multipart/form-data 

application/json 

text/xml

  

12、公司有用到第三方服务,出了问题,打电话给第三方,第三方不承认,这时候日志又显示不到错误,应该怎么处理

 

1、单独调用第三方服务,查看返回结果;

2、引入mock机制,假如正常返回的情况下,测试我们的系统是否存在问题;

3、建议开发增加日志,详细记录调用第三方接口的过程,记录调用前接口入参,返参等信息;

 

13、接口自动化中的关联怎么处理?

将请求返回的结果反射到类属性中,使用setattr()函数,下个请求调用这个类

14、自动化测试怎么校验结果?

使用断言,预期结果值和实际结果值进行对比;

15、自动化使用的测试框架是什么?简述自动化框架的设计、维护

1、自动化使用的测试框架:

语言:python

测试框架:unittest(assertEqual,assertTure,assertFalse)

接口调用:requests(API非常简洁)

数据驱动:ddt(装饰器:ddt类,unpack测试方法装饰器解包时候,data测试方法装饰器,可迭代的数据类型)

注:普通用户,管理用户,数据库,配置文件---基础数据

数据管理:openpyxl(excel,CSV,json,yaml,txt)

数据库交互:pymysql ---根据数据库选择相应的第三方模块来完成

数据格式的转换:eval,json

日志处理:logging ---清晰的执行过程,快速定位问题

持续集成:Jenkins(通过插件HTML Publisher/git/Email Extension)进行自动构建,生成HTML,发送邮件

 

2、自动化框架的设计、维护:

1、数据与代码分离,(数据驱动)==数据驱动框架==

例如:参数不一样,响应不一样

2、结构分层(数据层,用例层,逻辑性)

逻辑层:公用的方法,封装起来,避免用例层的代码冗余

数据层:例如,设计Excel,excel读取,参数化替换等

用例层:存放测试用例

 

16、在接口自动化测试中都用到了哪些包:

pymysql:连接数据库

ddt:

requests:

urllib:

xlrd:

xlwt:

xlutils:

 

17、根据什么来做断言?

1、协议状态码: 200,404,503   2、业务状态码:status:0   3、业务数据

 

18、具体的在这个项目中自动化怎么应用到实际的,您对自动化结果的分析

完成所有的自动化测试框架的设计和实现后,进行接口测试,然后集成到jenkins,配置定时执行,生成html报表,查看测试通过率,查看接口的功能

每次发版时,进行回归测试,新功能开发未提测前

 

19、做好测试计划的关键是什么?

明确测试目的,增强测试计划的实用性,保证测试用例的实用性和覆盖率,完全需求文档和规格指标书等,严格界定测试周期,测试轮次,测试覆盖模块等

20、super 是干嘛用的?在 Python2 和 Python3 使用,有什么区别?为什么要使用 super?请举例说明。

super 用于继承父类的方法、属性。super 是新式类中才有的,所以 Python2 中使用时,要在类名的参数中写 Object。Python3 默认是新式类,不用写,直接可用。使用 super 可以提高代码的复用性、可维护性。修改代码时,只需修改一处。

父类:

class Car():

    def __init__(self,make,model,year):

       self.make=make

       self.model=model

       self.year=year

def .....

 

class ElectricCar(Car):

    def __init__(self,make,model,year):     --------初始化父类的属性

       super().__init__(make,model,year):

    def ....

子类就可以使用父类的属性

 

posted @ 2020-11-06 23:25  小旭的blog  阅读(127)  评论(0编辑  收藏  举报