Python操作excel之openpyxl

1. 用例分离 

-- 一组测试数据-->一个用例-->测试类下的一个方法

-- 先用手工测试的用例:excel,xmind,tapd,testrail

测试数据的运转:手工写到excel中-->python读取excel数据-->自动化测试方法/函数

2. openpyxl

在我们读取excel前,需要安装一个第三方库,专门操作excel。

如:openpyxl(比较主流),xlrd(适合老版本,只能读取数据,不能写入等),pandas(比较重量级,安装的东西比较多,而且容易出错)

先来了解execl表格:
工作簿(workbook):指的就是整个excel文件

表格(sheet):一个工作簿中可以包括多个表格,也就是sheet1,sheet2....

行(row):就是sheet表格中的一行

列(column):就是sheet表格中的一列

单元格(cell):就是sheet表格中的一个格子

python读取excel操作步骤:

第一步:在桌面上新建了一个cases.xlsx表格,增加了两条数据,如下

 第二步:安装openpyxl,读取excel表格数据。如下

 安装完成后,开始读取数据

# 导入load_workbook:作用是加载工作簿
from openpyxl import load_workbook
# 通过文件得到一个工作簿,参数是文件名,如果有路径,要写绝对路径
wb = load_workbook('cases.xlsx')
print(wb)
# 获取 sheet 表格
sheet = wb['Sheet1'] # 注意S是大写的
print(sheet)
# 获取一个单元格
cell = sheet.cell(row=2,column=1)
print(cell)
# 获取单元格的值/内容
print(cell.value)

运行结果:

<openpyxl.workbook.workbook.Workbook object at 0x00000226B9510220>
<Worksheet "Sheet1">
<Cell 'Sheet1'.A2>
1

踩坑点:

 获取sheet中所有的数据:

# 导入load_workbook:作用是加载工作簿
from openpyxl import load_workbook
wb = load_workbook('cases.xlsx')
sheet = wb['Sheet1']
# 获取sheet中所有的数据
data = sheet.values
print(data) # 得到的一个结果generator的对象,这个是可以转换成列表格式
print(list(data))

运行结果:

<generator object Worksheet.values at 0x000001649E85F2E0>
[('case_id', 'title', 'data', 'expected'), (1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]

自动化测试过程不会每次都这样一行一行的写,我们会封装成一个函数,当使用的时候直接来调用函数

from openpyxl import load_workbook


# 封装读取excel的函数
def read_excel(file_name, sheet_name):
    # 获取工作簿
    wb = load_workbook(file_name)
    # 获取表格
    sheet = wb[sheet_name]
    # 获取表格中的数据
    data = list(sheet.values)
    return data


result = read_excel('cases.xlsx', 'Sheet1')
print(result)

运行结果:

[('case_id', 'title', 'data', 'expected'), (1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]

如果只想获取测试内容,不想要第一行内容,那么return的内容可以改成return data[1:],其他内容不用修改

from openpyxl import load_workbook


# 封装读取excel的函数
def read_excel(file_name, sheet_name):
    # 获取工作簿
    wb = load_workbook(file_name)
    # 获取表格
    sheet = wb[sheet_name]
    # 获取表格中的数据
    data = list(sheet.values)
    return data[1:]


result = read_excel('cases.xlsx', 'Sheet1')
print(result)

运行结果:

[(1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]

 如果不要第一行内容,时间长了,会不记得每个数据代表的是什么,所以我们要把[[ ],[ ],[ ]]/[( ),( ),( )]格式转换成[{ },{ },{ }],如何转换如下

from openpyxl import load_workbook
from pprint import pprint


# 封装读取excel的函数
def read_excel(file_name, sheet_name):
    # 获取工作簿
    wb = load_workbook(file_name)
    # 获取表格
    sheet = wb[sheet_name]
    # 获取表格中的数据
    data = list(sheet.values)
    return data


result = read_excel('cases.xlsx', 'Sheet1')
# [[ ],[ ],[ ]]/[( ),( ),( )]格式转换成[{ },{ },{ }]
new_list = []
for value in result[1:]:
    new_list.append(dict(zip(result[0],value)))
pprint(new_list)

运行结果:

[{'case_id': 1, 'data': '数据1', 'expected': '成功', 'title': '测试用例1'},
 {'case_id': 2, 'data': '数据1', 'expected': '失败', 'title': '测试用例2'}]

 3.excel结合测试用例使用

 unittest 是测试函数或类下面的方法是否可以正常使用,当测试人员自己写了个函数时,也是可以用unittest来进行测试是否可以正常使用的

第一步:准备测试数据,函数实际参数,放到了模块test_excel.py下

第二步:准备预期结果,放到了模块run_test_excel.py下

第三步:测试,调用read_excel函数,得到实际结果

test_excel.py模块具体代码如下:

from openpyxl import load_workbook


def read_excel(file_name, sheet_name):
    wb = load_workbook(file_name)
    sheet = wb[sheet_name]
    data = list(sheet.values)
    return data

run_test_excel.py模块具体代码如下:

import unittest
from test_excel import read_excel


class TestExcel(unittest.TestCase):
    def test_excel(self):
        file = 'cases.xlsx'
        sheet_name = 'Sheet1'
        expected = [('case_id', 'title', 'data', 'expected'), 
                    (1, '测试用例1', '数据1', '成功'),
                    (2, '测试用例2', '数据1', '失败')]
        actual = read_excel(file, sheet_name)
        self.assertEqual(expected, actual)

 运行结果:

但在实际工作中,不会这样去写一个类去测试自己写的测试用例,会使用下面的方法去测试

from openpyxl import load_workbook


def read_excel(file_name, sheet_name):
    wb = load_workbook(file_name)
    sheet = wb[sheet_name]
    data = list(sheet.values)
    return data


# 输入main会自动写全if __name__ == '__main__':
if __name__ == '__main__':
    data = read_excel('cases.xlsx', 'Sheet1')
    print(data)

按左边的播放键即可,但通过其他模块去调用此模块,不会运行main下的内容

运行结果:

 [('case_id', 'title', 'data', 'expected'), (1, '测试用例1', '数据1', '成功'), (2, '测试用例2', '数据1', '失败')]

 举个栗子:

 login.py模块具体代码如下:

def login(username=None, password=None):
    if username is None or password is None:
        return {"code": "400", "msg": "用户名或密码为空"}
    if username == 'yuz' and password == '123':
        return {"code": "200", "msg": "登录成功"}
    return {"code": "300", "msg": "用户名或密码错误"}

  test_login.py模块具体代码如下:

from login import login
import unittest


class TestLogin(unittest.TestCase):
    def test_login_01(self):
        username = ''
        password = ''
        expected = {"code": "400", "msg": "用户名或密码为空"}
        actual = login(username, password)
        self.assertEqual(expected, actual)

    def test_login_02(self):
        username = 'li'
        password = '123'
        expected = {"code": "300", "msg": "用户名或密码错误"}
        actual = login(username, password)
        self.assertEqual(expected, actual)

    def test_login_03(self):
        username = 'yuz'
        password = '123'
        expected = {"code": "200", "msg": "登录成功"}
        actual = login(username, password)
        self.assertEqual(expected, actual)

运行结果:

 这样去做自动化测试的缺点:

1. 一个用例要单独编写一个函数,存在重复性代码(可以通过数据驱动ddt解决)

2. 测试数据维护不方便,增加,修改,需要查找很多代码,一一修改(可以通过测试数据单独管理,如放到excel、yaml中)

 因此,我们改进放到一个自动化测试方法来完成所有测试用例,此时就需要用for循环

具体步骤如下:

第一步:新建一个login.xlsx表格来存放所有用例

 第二步:修改之前的test_excel.py,代码如下:

from openpyxl import load_workbook


def read_excel(file_name, sheet_name):
    wb = load_workbook(file_name)
    sheet = wb[sheet_name]
    data = list(sheet.values)
    # 取出表格中的第一行内容
    titles = data[0]
    # 用列表推导式转换成列表嵌套字典
    rows = [dict(zip(titles,row)) for row in data[1:]]
    return rows

 第三步:修改之前的test_login.py模块,代码如下:

import unittest
from login import login
from test_excel import read_excel

# 调用test_excel下的read_excel函数
data = read_excel('login.xlsx', 'Sheet1')


class TestLogin(unittest.TestCase):
    def test_login(self):
        # 循环列表嵌套字典的数据
        for row in data:
            # 循环取出每行数据,并转换成字典类型,因为取出的是str类型
            params = eval(row['data'])
            # 取出用户名与密码
            username = params['username']
            password = params['password']
            # 取出预期结果
            expected = row['expected']
            actual = login(username, password)
            self.assertEqual(expected, actual)

 注意:

1.excel当中读取的data单元格数据是字符串,不是字典。需要用evel()方法处理

2.使用for循环操作时,unittest把所有测试用例当成一个测试用例去执行,实际上有3个测试用例

4.数据驱动

为了优化for循环带来的问题,因此需要数据驱动来做参数化

参数化:对于一个统一的逻辑(测试函数),使用不同的参数(数据)去执行

使用第三方库来实现:ddt,unittestreport,使用前请先安装,切换到terminal,输入命令点击回车即可完成安装:pip install ddt;pip install unittestreport,已安装过忽略

4.1 unittestreport中ddt

import unittest
from login import login
from test_excel import read_excel
from unittestreport import ddt, list_data

# 调用test_excel下的read_excel函数
data = read_excel('login.xlsx', 'Sheet1')


@ddt
class TestLogin(unittest.TestCase):
    @list_data(data)
    def test_login(self,row):
        # row表示每次从data这个列表中取出一个数据,{}
        # row代表一组测试数据,相当于for row in data:
        # 源码:会自动生成一个新的test_login_1函数
        params = eval(row['data'])
        username = params['username']
        password = params['password']
        expected = eval(row['expected'])
        actual = login(username, password)
        self.assertEqual(expected, actual)

运行结果:

从结果可以看到,ddt的高级之处就是遇到了失败用例后,还会继续执行后面的测试用例,之间不会相互影响

参数化的具体使用过程:

1.导入unittestreport模块下的ddt,list_data

2.在测试函数当中,加入参数row,row参数是可以自己定义的

4.2 ddt 

import unittest
from login import login
from test_excel import read_excel
from ddt import ddt,data

# 调用test_excel下的read_excel函数
excel = read_excel('login.xlsx', 'Sheet1')


@ddt
class TestLogin(unittest.TestCase):
    # 一定要注意*
    @data(*excel)
    def test_login(self,row):
        # row表示每次从data这个列表中取出一个数据,{}
        # row代表一组测试数据,相当于for row in data:
        # 源码:会自动生成一个新的test_login_1函数
        params = eval(row['data'])
        username = params['username']
        password = params['password']
        expected = eval(row['expected'])
        actual = login(username, password)
        self.assertEqual(expected, actual)

运行结果:

 excel结合测试用例的用法总结:

为什么要用excel单独管理用例:便于维护

具体用法:

1.read_excel读取excel当中的数据

2.通过参数化完成,数据到用例的结合

3.用例函数只需要写一个,数据可能有多个甚至上万个,节省了很多的测试用例函数 

4.什么数据可以整合到一个用例函数?一定要是测试逻辑一致,只有数据不一致

注意事项:

1.excel当中不存在字典,如果单元格当中有文本,读出出来是字符串,字典是python当中的概念

2.参数化不要用for循环,因为for循环虽然一个函数可以执行多个数据,但是所有的数据被当成了一个测试用例,不会自动生成用例

参数化 vs 数据驱动

参数化:也就是函数参数,一个测试函数当中会参数,该参数往往就是测试数据

数据驱动(data driven testing,ddt):是一种思想,具体实现方式就是使用参数化

Guess you like

Origin blog.csdn.net/weixin_40611700/article/details/120565395