3.7 文件读写
在自动化测试过程中,要实现测试数据、配置等和测试脚本的分离,往往需要Python来处理各种类型的数据。因此,我们来学习一下相关的知识。
3.7.1 Python中的open函数
在做自动化测试的过程中,常会将一些系统配置、测试数据等保存到文件中。这时候就需要借助Python的open函数来操作文件。
我们先来看一个文件操作的简单示例(示例代码:test3_22.py)。
#通过open打开文件:第一个参数为文件名;第二个参数为模式;第三个参数为编码方式。 f = open(“test3_1.py”,“r”,encoding='utf8') # 通过read读取文件的全部内容 data = f.read() print(data) # 输出 f.close() # 关闭文件
对文件的操作步骤简单总结如下。
●打开文件,得到文件句柄并赋给变量。
●借助句柄对文件进行操作。
●关闭文件。
接下来,我们看一下open函数的完整语法格式。
open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)
参数说明如下。
●file:必选,文件路径(相对或者绝对路径)。
●mode:可选,文件打开模式,默认为“r”。
●buffering:设置缓冲。
●encoding:一般使用UTF-8。
●errors:报错级别。
●newline:区分换行符。
●closefd:传入的file参数类型。
mode的参数有多种取值方式,下面介绍一些常用的参数,如表3-3所示。
表3-3 文件打开模式mode的参数
接下来,我们再来看一下open函数创建的对象都可以使用哪些常见的方法,如表3-4所示。
表3-4 文件常见操作方法
接下来,我们用几个示例脚本来演示表3-4所示的方法如何应用。在Chapter_3目录下面新建一个“1.txt”文件,内容如下。
the first line the second line the third line the forth line the fifth line
示例一:通过read读取全部内容(示例代码:test3_23.py)。
f = open("1.txt","r",encoding='utf8') # 通过read读取文件全部内容 data1 = f.read() print("read对应的结果: {}".format(data1)) f.close() # 关闭文件
示例二:通过readline读取某行内容(示例代码:test3_24.py)。
f = open("1.txt","r",encoding='utf8') # 通过readline读取一行内容 data2 = f.readline() print("readline对应的结果: {}".format(data2)) f.close() # 关闭文件
示例三:通过readlines读取全部内容,返回列表(示例代码:test3_25.py)。
f = open("1.txt","r",encoding='utf8') # 通过readlines读取全部内容,返回列表 data3 = f.readlines() print("readlines对应的结果: {}".format(data3)) f.close() # 关闭文件
运行结果如下。
readlines对应的结果: ['the first line\n', 'the second line\n', 'the third line\n', 'the forth line\n', 'the fifth line']
示例四:通过write写入文字(示例代码:test3_26.py)。
f = open("2.txt","w",encoding='utf8') f.write('像Storm一样飞') f.close()
示例五:通过writelines将一个列表写入文件中。需要注意的是,如果不加换行符,则只会生成一行文字(示例代码:test3_27.py)。
f = open("3.txt","w",encoding='utf8') data = ['name\n','age\n','sex'] f.writelines(data) f.close()
注意▶ 我们读取文件是把内容读取到内存中的,如果不关闭它,就会一直占用系统资源,而且还可能导致其他的安全隐患。因此,这里提醒读者在通过open打开文件,操作完数据后,一定要记得使用close方法关闭文件。
为了避免忘记手动关闭文件,这里给大家推荐一种打开文件的新写法:with open。使用该方法,可以不用手动关闭文件(示例代码:test3_28.py)。
with open("1.txt", "r") as f: data = f.read() print(data)
3.7.2 JSON文件
在自动化测试过程中,我们会将部分数据保存到JSON(JavaScript Object Notation,JavaScript对象表示法)文件中,因此,学习使用Python处理JSON数据显得非常必要。JSON是一种常用的数据交换格式。JSON文件有以下特点。
●JSON是存储和交换文本信息的语法,类似XML。
●JSON比XML更小、更快、更易解析。
●JSON是轻量级的文本数据交换格式。
●JSON独立于语言。JSON使用JavaScript语法来描述数据对象,但是JSON仍然独立于语言和平台。JSON解析器和JSON库支持许多不同的编程语言。目前非常多的动态编程语言(PHP、JSP、.NET等)都支持JSON。
●JSON具有自我描述性,更易理解。
JSON的语法规则如下。
●JSON数据用大括号括起来。
●数据在“名称/值”对中,名称和值用冒号分隔,类似Python中的字典。
●名称必须用双引号引起来,值是否需要双引号引起来要视值的类型而定。
●数据由逗号分隔。
下面来看一个JSON格式的数据示例。
{"name":"storm", "age":30}
上面的JSON数据共有两个“名称/值”对,从格式上来看,和Python中的字典非常类似。实际上,我们在处理JSON数据时,很多情况下也确实将其转成字典来处理。不过需要注意的是,JSON数据必须用双引号引起来,不能使用单引号。
来看一下JSON值类型。
●数字(整数或浮点数),如{ "age":30 }。
●字符串(在双引号中),如{ "name":"Storm" }。
●逻辑值(True或False),如{ "flag":True }。
●数组(在中括号中),如{"sites": ["name","url"]}。
●对象(在大括号中),如{"student":{"name":"dzl"}}。
●null,如{“age”:null }。
JSON文件的扩展名为“.json”。在Chapter_3中新建一个文件,并命名为“test3_29.json”,代码如下。
{"name":"storm", "age":30, "sex": "男"}
Python 3.x版本自带json模块,不需要自己安装。json模块用于字符串和JSON数据类型间的转换,json模块提供了4个功能:dumps、dump、loads、load。
先来看dumps,其作用是将字典转换为字符串。
import json dict1 = {"name":"storm","age": 35} print(dict1) print(type(dict1)) # dumps将字典转换为字符串 j1 = json.dumps(dict1) print(j1) print(type(j1))
运行结果如下。
{'name': 'storm', 'age': 35} <class 'dict'> {"name": "storm", "age": 35} <class 'str'>
再来看dump,其作用是将字典转换为字符串,并写入JSON文件中。
import json dict1 = {"name":"storm","age": 30} print(dict1) print(type(dict1)) # 将字典数据写入txt文件 with open("1.txt","w") as f: j1 = json.dump(dict1,f) print(j1) print(type(j1))
运行结果如下。
{'name': 'storm', 'age': 30} <class 'dict'> None <class 'NoneType'>
然后看loads,其作用是将字符串转换为字典。
import json # str1是单引号引起来的字符串 str1 = '{"name":"storm","age": 30}' print(str1) print(type(str1)) # loads将字符串转换成字典 dic = json.loads(str1) print(dic) print(type(dic))
运行结果如下。
{"name":"storm","age": 30} <class 'str'> {'name': 'storm', 'age': 30} <class 'dict'>
最后看load,其作用是把文件打开,并把字符串转换为数据类型。
import json with open("1.txt",'r') as f: print(type(f)) dic = json.load(f) print(dic) print(type(dic))
运行结果如下。
<class '_io.TextIOWrapper'> {'name': 'storm', 'age': 30} <class 'dict'>
接下来,我们借助Python处理JSON文件。
◆读取字典类型的数据文件
在Chapter_3文件目录下创建一个名为“login_account.json”的文件,用来保存某个系统的登录账号信息,内容如下。
{ "user1":{"name":"storm","password":"123456"}, "user2":{"name":"duzl","password":"123123"} }
然后通过脚本读取该文件的内容。
import json file = "login_account.json" with open(file,'r') as f: users = json.load(f) print(type(f)) print(type(users)) print(users) for user in users: name = users[user]['name'] password = users[user]['password'] print(name,password)
运行结果如下。
<class '_io.TextIOWrapper'> <class 'dict'> {'user1': {'name': 'storm', 'password': '123456'}, 'user2': {'name': 'duzl', 'password': '123123'}} storm 123456 duzl 123123
◆读取列表类型的数据文件
同样,在Chapter_3文件目录下创建一个名为“myarray.json”的文件,内容如下。
[ { "name":"storm", "age":30 }, { "name":"lina", "age":22 } ]
然后我们用脚本读取文件中的数据。
import json file = "myarray.json" with open(file,'r') as f: ss = json.load(f) for s in ss: print(s) print(s["name"]) print(s["age"])
运行结果如下。
{'name': 'storm', 'age': 30} storm 30 {'name': 'lina', 'age': 22} lina 22
前面我们说了,在自动化测试过程中,我们经常会读取JSON文件。为了简化操作,我们可以封装一个读取JSON文件的函数,该函数支持解析两层的JSON文件。后续我们就可以直接调用该函数来解析JSON文件了,代码如下。
import json ''' 封装一下解析JSON文件的函数,支持两层的JSON文件,两个键 ''' def parse_json(file,key1,key2): mylist = [] with open(file,'r',encoding='utf8') as f: data = json.load(f) for i in data: mylist.append((data[i][key1],data[i][key2])) return mylist if __name__ == '__main__': account_info = parse_json('login_account.json', 'name','password') print(account_info)
3.7.3 YAML文件
在Web UI自动化测试中,我们可以将用到的配置信息保存在YAML格式的文件中。YAML是YAML Ain't a Markup Language的缩写。YAML的语法和其他高级语言类似,它用空白符号表示缩进,特别适合用来表达配置文件。该类型文件的扩展名为“.yml”,如storm.yml。
YAML文件的基本语法规则如下。
●大小写敏感。
●使用缩进表示层级关系。
●缩进不允许使用Tab键,只允许使用空格键。
●缩进的空格数不重要,只要相同层级的元素左对齐即可。
●“#”表示注释。
YAML文件支持多种数据类型。
●对象:键-值对的集合,又称为映射(mapping)、哈希(hashes)、字典(dictionary)。
●数组:一组按次序排列的值,又称为序列(sequence)、列表(list)。
接下来,我们通过代码来演示一下如何使用Python处理各种类型的YAML文件。PyYaml是Python中一个专门用于对YAML文件进行操作的模块。该模块同样可以借助pip来安装,安装命令如下。
C:\Users\duzil>pip3 install pyyaml
(1)YAML对象
这里,我们先准备一个名为“my_yaml_1.yml”的文件,内容如下。
url: "http://localhost:81/redmine/" ip: "127.0.0.1"
这里需要注意,冒号前面没有空格,冒号后面有一个空格。然后编写脚本来读取该文件。
import yaml with open('my_yaml_1.yml', 'r', encoding='utf8') as f: data = yaml.load(f, Loader=yaml.FullLoader) print(data) print(data['url']) print(data['ip'])
这里需要注意以下两点。
●我们通过yaml.load来处理YAML文件的内容。
●注意要加一个默认参数Loader=yaml.FullLoader。YAML 5.1版本后弃用了yaml.load(file)这个用法,但出于安全考虑需要指定Loader,通过默认加载器(FullLoader)可以禁止执行任意函数,这里了解即可。
运行结果如下。
{'url': 'http://localhost:81/redmine/', 'ip': '127.0.0.1'} http://localhost:81/redmine/ 127.0.0.1
(2)YAML数组
同样,我们先准备一个名为“my_yaml_2.yml”的文件,内容如下。
- storm - sk - shadow - queen
注意▶ “-”后面有一个空格。
然后通过脚本来处理该YAML文件。
import yaml with open('my_yaml_2.yml', 'r', encoding='utf8') as f: data = yaml.load(f, Loader=yaml.FullLoader) print(data)
运行结果如下。
['storm', 'sk', 'shadow', 'queen']
(3)YAML复合结构
同样,我们先准备一个名为“my_yaml_3.yml”的文件,内容如下。
websites: URL: http://localhost/ IP: 127.0.0.1 Port: 81
然后通过脚本来读取该YAML文件。
import yaml with open('my_yaml_3.yml', 'r', encoding='utf8') as f: data = yaml.load(f, Loader=yaml.FullLoader) print(data) print(data['websites']['URL']) print(data['websites']['IP']) print(data['websites']['Port'])
运行结果如下。
{'websites': {'URL': 'http://localhost/', 'IP': '127.0.0.1', 'Port': 81}} http://localhost/ 127.0.0.1 81
在Web UI自动化测试中,可以将系统用到的配置信息以复合结构保存到一个特定文件中。因此,我们可以封装一个函数来读取YAML文件的信息,文件名为“parse_yml.py”,脚本如下。
import yaml ''' 通过传递文件名、section和key,读取YAML文件中的内容 ''' def parse_yml(file, section, key): with open(file, 'r', encoding='utf8') as f: data = yaml.load(f, Loader=yaml.FullLoader) return data[section][key] if __name__ == '__main__': value = parse_yml('my_yaml_3.yml', 'websites', 'URL') print(value)
3.7.4 CSV文件
在自动化测试过程中,可以将相对复杂的测试数据放置到表格中,如放置到Excel或CSV(Comma Separated Values,逗号分隔值,有时也称为字符分隔值,因为分隔字符也可以不是逗号)文件中。
Excel文件大家相对比较熟悉,Python有丰富的第三方库来处理Excel文件,需要注意的是Excel文件扩展名分为“.xls”和“.xlsx”,需要不同的库来处理。不过本书不介绍如何使用Python处理Excel文件,而是介绍一种更简洁、更轻量的文件格式:CSV。该文件以纯文本形式存储表格数据(数字和文本)。
日常工作中,大家经常用Excel或WPS来打开扩展名为“.csv”的文件,实际上完全可以使用写字板来打开它,你会发现它是一种用逗号分隔的数据文件,如图3-3所示。
图3-3 CSV文件
接下来,我们在Chapter_3目录下新建一个CSV文件,并命名为“my_csv_1.csv”,文件内容如下。
name,password,status admin,error,0 admin,rootroot,1
借助代码来读取文件,步骤如下。
●导入csv模块。
●借助csv.reader来处理数据。
import csv with open('my_csv_1.csv', 'r', encoding='utf8') as f: data = csv.reader(f) print(data) for i in data: print(i)
运行结果如下。
<_csv.reader object at 0x0077E4B0> ['name', 'password', 'status'] ['admin', 'error', '0'] ['admin', 'rootroot', '1']
在自动化测试中,我们经常需要将CSV文件中的数据返回为一个嵌套列表,这样可以将数据作为测试的参数来使用(后面章节将详细介绍)。因此,我们可以封装一个函数来实现该功能。示例代码:parse_csv.py。
import csv def parse_csv(file): mylist = [] with open(file, 'r', encoding='utf8') as f data = csv.reader(f) for i in data: mylist.append(i) del mylist[0] # 删除标题行的数据 return mylist if __name__ == '__main__': data = parse_csv('my_csv_1.csv') print(data)
本节介绍了如何使用Python读取JSON、YAML、CSV文件中的内容,后续我们会将这些知识应用到自动化测试框架中,希望大家掌握。
注意▶ 文件名中别用居中的横杠,虽然不会报错,但是在文件相互调用的时候会出现失败的情况,建议使用下划线来代替居中的横杠。