python测试(13-14)

1.实例方法的一些补充

如何确定使用的是实例方法: 一个很明显的方法就是看参数里面是否有 self,带有self的就是代表使用了实例方法

例如:

class Car:
    def __init__(self,color,logo):
        self.logo = logo
        self.color = color
        print(f"{self.color}{self.logo}正在加油...")
car = Car('白色','劳斯莱斯')

结果:白色的劳斯莱斯正在加油…

上述代码中,方法中有self参数,这就是一个很典型的实例方法

初始化函数在使用时,不用再去重新调用,因为该代码可以自动调用。但是别的函数不可以

class Car:
    def __init__(self,color,logo):
        self.logo = logo
        self.color = color
        print(f"{self.color}{self.logo}正在加油...")
    def food(self,cl,tas):
        self.color = cl
        self.taste = tas
        print(f"{self.color}很好看")
car = Car('白色','劳斯莱斯')
car.food('绿色','辣')

这段代码中有两个方法,但是在直接使用类名加括号时,里面的参数只能是初始化函数的。如果没有初始化函数,但是却使用了该函数是会报错的

2.类方法

类方法就是指通过类调用的方法

类方法有一个特别明显的特征:在要定义一个类方法而不是实例方法时,要在首行写@classmethod

例如:

@classmethod
def people(cls,wt,ht):
    cls.weight = wt
    cls.height = ht
    print(f"身高{cls.height},体重{cls.weight}")

这就是代表一个类方法

其中的cls与实例方法中的self作用一样,在调用时可以直接代表一个类

class Car:
    def __init__(self,color,logo):
        self.logo = logo
        self.color = color
        print(f"{self.color}{self.logo}正在加油...")
    def food(self,cl,tas):
        self.color = cl
        self.taste = tas
        print(f"{self.color}很好看")
    @classmethod
    def people(cls,wt,ht):
        cls.weight = wt
        cls.height = ht
        print(f"身高{cls.height},体重{cls.weight}")
car = Car('白色','劳斯莱斯')
car.people(50,165)

上述代码中的cls相当于car这个类,cls就是代表想应的类

上述代码是通过类去调用的这个方法,但是也可以使用对象或者说是实例去调用这个方法。在类方法中也是对象会满足所有的类的属性,但是反过来是不确定的,所有不可以使用类去调用一个对象的方法

类方法在实际情况下使用的比较少,更多的使用的是实例方法,如果在实例方法和类方法中拿不定主意,建议直接使用实例方法

3.静态方法

静态方法在作用上其实与普通的函数没有什么区别,因为它即不可以操作类,也不可以操作对象,里面即没有self,也没有cls。所有不会有什么实际上的别的作用,但是设计上来看会比较方便管理。

静态方法和类方法一样很好去识别,因为它和类方法一样要加前缀,但是它加的是staticmethod

例如:

@staticmethod
def fly():
    print('飞起来')

通过上面的代码能够很明显的看出其与普通函数在作用上并没有什么区别。它也是和类方法一样即可以通过类来调用也可以用对象来调用

4.继承

在一个程序中一般会由很多的类构成,假如一个类是另一个类的子类,其实就是相当于这个子类有和父类中一样的属性。假如已经存在一个类,里面写入了很多的方法,那么当后续有类需要使用时就不需要再重新去写。这个就有点和之前的函数一样,如果不用函数,就会出现很多的冗余代码,十分的繁琐,并且很容易出错,所有倒不如直接直接用一种方法去直接继承。

继承的语法:直接在类名后的括号里面加入另外一个类名,外面的是子类,括号里面的是被继承的父类。

例如:

python测试(13-14)_第1张图片

上述代码创建了一个MyCar的子类,Car是它继承的父类。因为子类继承了父类,所以子类可以使用父类所有的方法和属性。比如上面,通过子类MyCar也可以直接调用fly方法,并且也能直接实现。

但是对于一个新的类来说,它不可能只含有父类的方法,它肯定会自己有自己的新方法。如果想要实现自己的新方法其实很简单,就是直接在里面定义方法,可以是类方法也可以是实例方法

例如:

class MyCar(Car):
    def wyj(self,ne):
        self.name = ne
        print(f"最爱{self.name}")
mycar = MyCar('红色','劳斯莱斯')
mycar.wyj('猪八戒进进宝')

它的调用方法与其他类的方法一样,以上述代码为例,因为wyj是一个实例方法,所以必须要通过实例来调用。

但是需要注意的是父类不可以使用子类的方法属性,因为子类中的方法是独属于子类的,与父类没有关系

假如说,子类中定义了一个与父类中相同的属性,那么在后续的调用中会使用子类中的属性,就是相当于方法被重写了。就相当于我们去继承某项技术,它有优点也有缺点,那么我们可以继承它的优点,当遇到不那么想要的我们也可以直接在子类里面修改

例如:

class Car:
    def __init__(self,color,logo):
        self.logo = logo
        self.color = color
        print(f"{self.color}{self.logo}正在加油...")
    def food(self,cl,tas):
        self.color = cl
        self.taste = tas
        print(f"{self.color}很好看")
    @classmethod
    def people(cls,wt,ht):
        cls.weight = wt
        cls.height = ht
        print(f"身高{cls.height},体重{cls.weight}")
    @staticmethod
    def fly():
        print('飞起来')
car = Car('白色','劳斯莱斯')
car.people(50,165)
class MyCar(Car):
    def wyj(self,ne):
        self.name = ne
        print(f"最爱{self.name}")
    def food(self):
        print('hhh,你被替代了')

mycar = MyCar('红色','劳斯莱斯')
mycar.wyj('猪八戒进进宝')
mycar.food()

父类里面定义了一个food类,子类里面也定义了一个food类,当后面子类去调用时会使用自己修改后的那个。但是!!!当使用父类去调用的时候还是原来那个,就是相当于那个属性只是在子类调用时被改变了,并没有把父类的改变了。

当父类子类两种都想使用时该怎么办呢?

可以直接在子类方法中使用super(),就可以去调用父类中的方法,一般是同名方法,但是也可以调用非同名方法

例如:

python测试(13-14)_第2张图片

这样就即可以 使用父类的方法打印出 红色很好看

也可以 使用子类的方法打印出 hhh,你被替代了

如果说其他第三个类或者说更多的类使用了继承,比如上述,再来一个新类继承了第二个类MyCar,那么第三个类就同时具有前两个类的属性,相当于是孙子类。如果第三个类是继承的第一个Car类,那么第二个和第三个就是平辈,没有直接的关系,只具有Car里面的属性

一个类不仅可以继承一个类,也可以继承多个类,相当于一个人可以继承几种手艺。那么它就可以同时拥有他继承的多个父类的所有属性

class Car:
    def __init__(self,color,logo):
        self.logo = logo
        self.color = color
        print(f"{self.color}{self.logo}正在加油...")
    def food(self,cl,tas):
        self.color = cl
        self.taste = tas
        print(f"{self.color}很好看")
    @classmethod
    def people(cls,wt,ht):
        cls.weight = wt
        cls.height = ht
        print(f"身高{cls.height},体重{cls.weight}")
    @staticmethod
    def fly():
        print('飞起来')
car = Car('白色','劳斯莱斯')
car.people(50,165)
class Play:
    def play_(self):
        print('唱一首歌')
class MyCar(Car,Play):
    def wyj(self,ne):
        self.name = ne
        print(f"最爱{self.name}")
    def food(self):
        super().food('红色','甜')
        print('hhh,你被替代了')

mycar = MyCar('红色','劳斯莱斯')
mycar.wyj('猪八戒进进宝')
mycar.food()
mycar.play_()

此处MyCar就是同时继承了Car类和Play类

重写初始化函数

子类虽然可以继承父类,但是也可以重写初始化函数

class Tesila(Car):
    def __init__(self,cl):
        self.color = cl
        self.logo = '特斯拉'

因为这个类就是特斯拉这个车,属于车的子类,所以logo可以直接写定,有一个color就行

还有另外一种方法就是使用super函数

class Tesila(Car):
    def __init__(self,color='蓝色'):
        super().__init__(color,'奥迪')

使用super调用之前Car的初始化函数,颜色写在定义时的参数里,最后一行super那个代码就是相当于倒数第二个代码的倒数后两行

5.对类或者对象的属性进行相关的动态操作

相关的动态操作包括:对类或者对象的属性进行添加、获取、修改、删除

1.添加类或者对象的属性 setattr:

setattr(类/对象,属性名,属性值),此处的属性名一般是字符串的形式

例如:

class Data:
    def hello(self):
        print('hello,world!')
setattr(Data,'wyj','猪八戒')
data = Data()
print(data.wyj)

上述代码就是在原来的类Data上添加一个属性,名字(属性名)为wyj,属性值为 猪八戒

结果:

python测试(13-14)_第3张图片

这样就是动态的给类添加了一个属性,在对这段代码进行编译时可以很明显的看出,在最后一行中属性名即wyj被标上了黄色,被标上黄色是编译器提醒可能出错了,要去修改。但是在这里是没有错误的,因为编译器在对代码进行检查的时候是按照静态的方法来检查的,因为这种方法是动态的,那么自然,按照顺序,在Data类中确实找不到wyj这个属性,所以会标上黄色,但是当这个代码去执行的时候它会是正确的。

2.获取类或者对象的属性 getattr

**getattr(类/对象,属性名)**此处的属性名依旧是以字符串的形式

例如:

class Data:
    def hello(self):
        print('hello,world!')
setattr(Data,'wyj','猪八戒')
data = Data()
print(data.wyj)
print(getattr(Data,'wyj'))

这个操作相当于倒数第二行和倒数第三行的代码的作用,那两行代码就是先用去创建一个对象,然后再通过对象去获取它的wyj属性。

而这个操作即最后一行就是直接打印获得的类的wyj属性

3.判断类或者对象是否有某个属性 hasattr

hasattr(类/对象,属性名) 此处的属性名依旧是以字符串的形式

例如:

class Data:
    def hello(self):
        print('hello,world!')
setattr(Data,'wyj','猪八戒')
print(getattr(Data,'wyj'))
print(hasattr(Data,'wyj'))

结果:True

从结果来看,结果是布尔类型

4.删除类或者对象的属性 delattr

delattr(类/对象,属性名) 此处的属性名依旧是以字符串的形式

例如:

class Data:
    def hello(self):
        print('hello,world!')
setattr(Data,'wyj','猪八戒')
print(getattr(Data,'wyj'))
if hasattr(Data,'wyj'):
    delattr(Data,'wyj')
print(Data.wyj)

结果:报没有wyj这个属性名的属性

根据结果来看,说明wyj这个属性已经被删掉了

6.excel的相关操作

在接口自动化中会用到excel的数据管理,所以要学习相关操作

python相比于其他语言来说,它的特点在于它具有很多不同的第三方库,可以完成同一件事

如何在编辑器里读取excel表格里面的内容?

可以使用第三方库xlrd,它只支持以 .xls为后缀的文件,但是这个库它的作用只能读取里面的内容并不能写入内容

如何在编辑器里将内容写进excel表格里面?

可以使用第三方库xlwt,它也是只支持以.xls为后缀的文件,这个库它的作用只能写入内容但是不能读取excel里面的内容

这两种库在实际上用的比较少,有一种库,同时支持读取和写入。还有一种工具也可以实现

工具:pandas

该工具的功能十分强大,是基于Numpy的工具,是为了解决数据分析而生的,它包含了很多的库和一些数据模型。它可以处理excel里面的数据,但是这种方式一般是在数据量特别多的时候才使用,一般情况时不用。

库:openpyxl

它是一种专门针对excel里的数据的库,读写一体,可支持xlsx``xlsm``xltx``xltm为后缀的文件

安装方法:

第一种:在控制台输入 pip install openpyxl 就可以直接安装该库

第二种:菜单—设置—项目—py解释器—输入想要添加的库(不要勾选下面的选项)—安装成功

excel中有三个基本的概念:

工作簿:workbook,是指excel打开后的整个界面,相当于一个文件

表单:sheet,工作簿中往往可以自己分很多的表单,点击左下角就可以增加表单的个数

单元格:cell,一个表单中的具体的空格就是单元格,数据就是写在单元格里的

在编辑器中获得excel里面的文件:

1.先打开excel,一般会现在excel里面把数据先写好,要保存在和写的相关代码的同一个文件夹下面!!!

2.导入load_workbook,在编辑器中输入 from openpyxl import load_workbook,这个操作就是为了读取excel里面的数据。利用load_workbook导入excel的路径,比如:load_workbook(r"excel表格的存放路径"),这个可以用一个变量去存储

3.假如说想获取工作簿中所有表单的名称,那么可以使用 变量名.sheetnames

例如:

from openpyxl import load_workbook
wb = load_workbook(r"D:\python\My_Code\day1\day1 _try\测试用例.xlsx")
print(wb.sheetnames)

代码运行结果:

[‘Sheet1’, ‘Sheet2’, ‘Sheet3’]

excel界面:

python测试(13-14)_第4张图片

由该工作簿截图可看出,其含有三个表单,sheet1 sheet2 sheet3

该表单与代码运行出来的表单是一致的

所以说sheetnames方法是用来获得表单名称的

如果说想获得在这个工作簿中最活跃的表单,可以用active方法,就可以在多个表单中获取使用最活跃的那一个

例如:

from openpyxl import load_workbook
wb = load_workbook(r"D:\python\My_Code\day1\day1 _try\测试用例.xlsx")
print(wb.sheetnames)
print(wb.active)

结果:

[‘Sheet1’, ‘Sheet2’, ‘Sheet3’]

根据上面工作簿的截图来看,数据都是在sheet3里面的,所以sheet3是最活跃的,而结果也刚好验证了这一点

如果想对指定的表单进行操作,可以使用变量名['表单名']

比如我想对sheet3进行操作,那么:

from openpyxl import load_workbook
wb = load_workbook(r"D:\python\My_Code\day1\day1 _try\测试用例.xlsx")
print(wb.sheetnames)
print(wb.active)
sh = wb['Sheet3']

即可

使用该方法之后就可以对获得的表单进行操作,读取打印,写入等等。比如现在想去获得整个表单里面的值:

print(sh.values)

但是这样打印出来的只是显示它是一个对象,想要获得实际的值还要转化为列表,即:

print(list(sh.values))

结果:

[(‘用例名称’, ‘接口地址’, ‘请求方法’, ‘请求数据’, ‘期望结果’), (‘登录成功’, ‘http://lemonban.com/log’, ‘post’, ‘{“name”:“dan”,“password”:“123”}’, True), (‘登录失败’, ‘http://lemonban.com/log’, ‘post’, ‘{“name”:“dan”,“password”:“123456”}’, False), (‘登录失败-密码少于三位’, ‘http://lemonban.com/log’, None, ‘{“name”:“dan”,“password”:“12”}’, False)]

PS:在控制台上是在一行显示的,但是这里由于没有那么宽,所以只能打印多行。打印的方式是列表里面嵌套元组,

python测试(13-14)_第5张图片

根据上述截图可看出,每一个元组里面的内容是每一行的内容

关于读取出来的数据类型的问题

1.如果说单元格里面只有数字,那么读取出来就会转化成为整数类型或者浮点类型

2.如果说单元格里面没有任何的输入,那么读取出来就会是None(请注意这里的没有任何输入,输入一个空格也是输入了,最后在读取的时候会用一个字符串去接受这个空格)

3.如果单元格里面只有true/false,那么读取出来的就是布尔类型

4.如果单元格中只有时间格式,比如2023/10/14,那么读取出来就是以datetime的形式

如果以上都不是,那么读取出来就是字符串。

如何操作单个单元格?

获得单个单元格:

第一种:表单名.cell(行号,列号).value

例如:

sh.cell(2,1).value

第二种:表单名[‘行和列’].value

例如:

sh['A2'].value

第二中相对于第一种来说比较简便一些,但是他们表达的意思是一样的

修改单个单元格:

表单名[‘行和列’].value = 新值

用新值覆盖旧的那个就可以修改了

但是需要注意的是修改了之后再去运行还是会和之前一样,因为没有进行保存操作。如果想要值发生改变,那么就要保存

关于保存操作

使用save函数:

sh['A2']= '已经登录'
wb.save(r"D:\python\My_Code\day1\day1 _try\工作簿1.xlsx")
print(sh['A2'].value)

这个步骤就是将A2位置的单元格进行修改成为“已经登录”,然后再使用save函数,里面加上之后的路径,可以使用原来的路径,也可以另存到一个新的表单。如果是使用原来的路径的话,有一个地方需要注意:写完后,进行编译,会报错显示没有权限,因为如果已经打开了excel表格,在这里又重新打开会收到限制,不会让其打开,所以要先关掉原来的再去打开。

将excel表格里的多组数据打包成字典

tuple1 = ('用例名称', '接口地址', '请求方法', '请求数据', '期望结果')
tuple2 = ('已经登录', 'http://lemonban.com/log', 'post', '{"name":"dan","password":"123"}', True)
a = dict(zip(tuple1,tuple2))
print(a)

zip函数,zip(关键词,值)

如果a不转化成为字典,那么得到的就是一个对象

如果有多组数据:

from openpyxl import load_workbook
wb = load_workbook(r"D:\python\My_Code\day1\day1 _try\工作簿1.xlsx")
sh = wb['Sheet3']
sh1 = list(sh.values)
print(sh1[0])
print(sh.cell(2,1).value)
sh['A2']= '已经登录'
wb.save(r"D:\python\My_Code\day1\day1 _try\工作簿1.xlsx")
tuple1 = ('用例名称', '接口地址', '请求方法', '请求数据', '期望结果')
tuple2 = ('已经登录', 'http://lemonban.com/log', 'post', '{"name":"dan","password":"123"}', True)
tuple3 = ('登录失败', 'http://lemonban.com/log', 'post', '{"name":"dan","password":"123456"}', False)
tuple4 = ('登录失败-密码少于三位', 'http://lemonban.com/log', None, '{"name":"dan","password":"12"}', False)
for tuple in sh1[1:]:
    b = dict(zip(sh1[0],tuple))
    print(b)

先将表单中的表头单独拿出来,在上述代码中就是sh1[0],然后用for循环遍历sh1[1:],再一一进行打包

打包操作结果:

{'用例名称': '已经登录', '接口地址': 'http://lemonban.com/log', '请求方法': 'post', '请求数据': '{"name":"dan","password":"123"}', '期望结果': True, '测试时间': datetime.datetime(2023, 10, 14, 0, 0)} {'用例名称': '登录失败', '接口地址': 'http://lemonban.com/log', '请求方法': 'post', '请求数据': '{"name":"dan","password":"123456"}', '期望结果': False, '测试时间': datetime.datetime(2023, 10, 14, 0, 0)} {'用例名称': '登录失败-密码少于三位', '接口地址': 'http://lemonban.com/log', '请求方法': None, '请求数据': '{"name":"dan","password":"12"}', '期望结果': False, '测试时间': datetime.datetime(2023, 10, 14, 0, 0)}

此处本来是一行对应一个结果

7.自定义excel操作类

自定义excel操作类就是封装一个自己要用的类,而什么叫做封装呢?封装其实就是指定义一个类,方法在类的内部实现,外部直接进行调用就好,不用管是怎么实现的。

在进行封装之前要先想清楚:

这个类要实现什么功能?有哪一些方法,要根据场景来

1.先选取一个表单、

2.读取表单里面的数据

是否要进行初始化?哪些需要进行初始化

比如表单的路径和表单的名称

例如:

from openpyxl import load_workbook
class HandExcel:
    def __init__(self,path,name):
        try:
            wb = load_workbook(path)
            sh = wb[name]
        except:
            print('出现错误了,可能是路径错误也有可能是名称错误')
        raise
    def get_all_date(self):
        c = []
# 先拿到表单的所有数据
        wb1 = load_workbook(r"D:\python\My_Code\day1\day1 _try\工作簿1.xlsx")
        sh1 = wb1['Sheet3']
        all_date = list(sh1.values)
# 再去拿到表头
        a1 = all_date[0]
# 再进行打包操作
        for a in all_date[1:]:
            b = dict(zip(a1,a))
            c.append(b)
        return c

一个封装类里面包括了两个方法,初始化函数中初始化了excel的路径,和表单的名称。

get_all_date函数就是将数据打包的过程

如何使用:

先将初始化函数实例化之后赋予给一个变量,就是打开一个具体的表单。然后使用get_all_date函数获得表单里面的内容

关于 if __name__ == '__main__'

他的作用就是控制某段代码再被导入到其他文件时不被使用

例如:

from openpyxl import load_workbook
class HandExcel:
    def __init__(self,path,name):
        try:
            wb = load_workbook(path)
            sh = wb[name]
        except:
            print('出现错误了,可能是路径错误也有可能是名称错误')
        raise
    def get_all_date(self):
        c = []
# 先拿到表单的所有数据
        wb1 = load_workbook(r"D:\python\My_Code\day1\day1 _try\工作簿1.xlsx")
        sh1 = wb1['Sheet3']
        all_date = list(sh1.values)
# 再去拿到表头
        a1 = all_date[0]
# 再进行打包操作
        for a in all_date[1:]:
            b = dict(zip(a1,a))
            c.append(b)
        return c
if __name__ == '__main__':
    he = HandExcel(r"D:\python\My_Code\day1\day1 _try\工作簿1.xlsx", 'sheet3')
    cases = he.get_all_date()
    print(cases)

代码在最后4行。这段代码存在一个文件中,在哪个文件在执行哪个就是主文件,即入口。但是后来在别的文件中被调用的时候,是别的文件是入口,即主文件,所以说原来的文件已经不是主入口了,所以if的条件为假,故不会执行。一般写在最后面

你可能感兴趣的:(python,开发语言,功能测试,pycharm,自动化)