首页 > 技术文章 > 自动化测试框架-数据驱动(2)

test-chen 2019-05-13 18:32 原文

5、使用Excel进行数据驱动测试
测试逻辑:
(1)打开百度首页,从Excel文件中读取测试数据作为搜索关键词
(2)在搜索输入框中输入读取出搜索关键词
(3)单击搜索按钮
(4)断言搜索结果页面中是否出Excel文件中提供的预期内容,包含则认为测试执行成功,否则认为失败

测试数据准备:
在本地磁盘D:\test\DataDrivenTesting目录中新建一个“测试数据.xlsx”,工作表名为“搜索数据表”,内容如下“
序号 搜索词 期望结果
1 邓肯 蒂姆
2 乔丹 迈克尔
3 库里 斯蒂芬

实例代码:
在Pycharm中新建一个ExcelDataDrivenProject的Python工程,工程下新建两个文件,文件名分别为ExcelUtil.py和DataDrivenByExcel.py和DataDrivenByExcel.py
ExcelUtil.py文件用于编写读取Excel的脚本,具体内容如下:

#encoding=utf-8
from openpyxl import load_workbook

class ParseExcel(object):

    def __init__(self, excelPath, sheetName):
        # 将要读取的excel加载到内存
        self.wb = load_workbook(excelPath)
        # 通过工作表名称获取一个工作表对象
        self.sheet = self.wb.get_sheet_by_name(sheetName)
        # 获取工作表中存在数据的区域的最大行号
        self.maxRowNum = self.sheet.max_row

    def getDatasFromSheet(self):
        # 用于存放从工作表中读取出来的数据
        dataList = []
        for line in self.sheet.rows:
            # 遍历工作表中数据区域的每一行,
            # 并将每行中各个单元格的数据取出存于列表tmpList中,
            # 然后再将存放一行数据的列表添加到最终数据列表dataList中
            tmpList = []
            tmpList.append(line[1].value)
            tmpList.append(line[2].value)
            dataList.append(tmpList)
        # 将获取工作表中的所有数据的迭代对象返回
        # 因为工作表中的第一行是标题行,所以需要去掉
        return dataList[1:]

if __name__ == '__main__':
    excelPath = u'D:\\test\\DataDrivenTesting\\测试数据.xlsx'
    sheetName = u"搜索数据表"
    pe = ParseExcel(excelPath, sheetName)
    print pe.getDatasFromSheet()
    for i in pe.getDatasFromSheet():
        print i[0], i[1]

  DataDrivenByExcel.py文件用于编写数据驱动测试脚本代码,具体内容如下:

#encoding=utf-8
import unittest,time
import logging,traceback
import ddt
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from ExcelUtil import ParseExcel

#初始化日志对象
logging.basicConfig(
    #日志级别
    level = logging.INFO,
    #日志格式
    #时间、代码所在文件名、代码行号、日志级别名、日志信息
    format = "%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s",
    #打印日志的时间
    datefmt = "%a,%d %b %Y %H: %M: %S",
    #日志文件存放的目录(目录必须存在)及日志文件名
    filename = "D:\\test\\DataDrivenTesting\\report.log",
    #打开日志文件的方式
    filemode = "w"
)

excelPath = u"D:\\test\\DataDrivenTesting\\测试数据.xlsx"
sheetName = u"搜索数据表"
#ParseExcel类的实例对象
excel = ParseExcel(excelPath,sheetName)

@ddt.ddt

class TestDemo(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Ie(executable_path = "D:\\IEDriverServer")

    @ddt.data(*excel.getDatasFromSheet())
    def test_dataDrivenByExcel(self,data):
        testdata,expectdata = tuple(data)
        url = "http://www.baidu.com"
        self.driver.get(url)
        self.driver.maximize_window()
        #设置隐式等待时间为10秒
        self.driver.implicitly_wait(10)

        try:
            #找到搜索框,并输入测试数据
            self.driver.find_element_by_id("kw").send_keys(testdata)
            #找到搜索按钮并单击
            self.driver.find_element_by_id("su").click()
            time.sleep(3)
            #断言期望结果是否出现在页面源代码中
            self.assertTrue(expectdata in self.driver.page_source)
        except NoSuchElementException,e:
            logging.error(u"查找的页面元素不存在,异常堆栈信息:"+str(traceback.format_exc()))
        except AssertionError, e:
            #注意引号格式
            logging.info(u"搜索“%s”,期望“%s”,失败" % (testdata, expectdata))
        except Exception, e:
            logging.error(u"未知错误,错误信息:" + str(traceback.format_exc()))
        else:
            logging.info(u"搜索“%s”,期望“%s”,通过" % (testdata, expectdata))

    def tearDown(self):
        self.driver.quit()

if __name__ == "__main__":
    unittest.main()

不使用ddt和uniitest的Excel数据驱动,DataDrivenByExcel.py:

#encoding=utf-8
from selenium import webdriver
import time
import datetime
from openpyxl import *
wb = load_workbook(u"D:\\test\\DataDrivenTesting\\测试数据.xlsx")
ws = wb.active  #获取第一个sheet
print u"最大行号:", ws.max_row

driver = webdriver.Ie(executable_path = "D:\\IEDriverServer")
test_result = []
#Excel的行是从1开始的,所以我们从第二行开始遍历(第一行是标题)
#且使用切片时,必须有结束行的索引号,不能写成[1:],这样会报错
#Excel的列号是从0开始的,列读取以出来后是一个元组
for row in ws[2:ws.max_row]:
    print row[1],row[2]
    try:
        driver.get("http://www.baidu.com")
        driver.find_element_by_id("kw").send_keys(row[1].value)
        driver.find_element_by_id("su").click()
        time.sleep(3)
        assert row[2].value in driver.page_source
        row[3].value = time.strftime("%Y-%m-%d %H:%M:%S")
        row[4].value = u"成功"
    except AssertionError,e:
        row[3].value = time.strftime("%Y-%m-%d %H:%M:%S")
        row[4].value = u"断言失败"
    except Exception,e:
        row[3].value = time.strftime("%Y-%m-%d %H:%M:%S")
        row[4].value = u"出现异常失败"

driver.quit()
wb.save(u"D:\\test\\DataDrivenTesting\\测试数据.xlsx")


6、使用XML进行数据驱动测试
测试逻辑:
(1)打开百度首页,从XML文件中读取测试数据作为搜索关键词
(2)在搜索框中输入读取出的搜索关键词
(3)单击搜索按钮
(4)断言搜索结果页面中是否出现了XML文件中提供的预期内容,包含则认为测试执行成功,否则认为失败

实例代码:
在PyCharm中新建一个名叫XMLDataDrivenProject的Python工程,并在工程下新建三个文件,文件名分别为XmlUtil.py、TestData.xml以及DataDrivenByXML.py
TestData.xml文件用于存放测试数据,具体内容如下:

<?xml version = "1.0" encoding = "utf-8"?>
<bookList type = "technology">
    <book>
        <name> Selenium WebDriver 实战宝典</name>
        <author>吴晓华</author>
    </book>
    <book>
        <name> HTTP 权威指南</name>
        <author>古尔利</author>
    </book>
        <book>
        <name>探索式软件测试</name>
        <author>惠特克</author>
    </book>
</bookList>

  XmlUtil.py文件用于解析xmlutil.py文件,获取测试数据,具体内容如下:

#encoding=utf-8
from xml.etree import ElementTree

class ParseXML(object):
    def __init__(self,xmlPath):
        self.xmlPath = xmlPath

    def getRoot(self):
        #打开将要解析的XML文件
        tree = ElementTree.parse(self.xmlPath)
        #获取XML文件的根节点对象,也就是树的根,然后返回给调用者
        return tree.getroot()

    def findNodeByName(self,parentNode,nodeName):
        #通过节点的名字,获取节点对象
        nodes = parentNode.findall(nodeName)
        return nodes

    def getNodeOfChildText(self,node):
        #获取节点node下所有子节点的节点名作为key,本节点作为value组成的字典对象
        childrenTextDick = {i.tag:i.text for i in list(node.iter())[1:]}
        #上面代码造价于下面代码
        """
        childrenTextDick = {}
        for i in list(node.iter())[1:]:
            childrenTextDick[i.tag] = i.text
        """
        return childrenTextDick

    def getDataFromXml(self):
        #获取XML文档树的根节点对象
        root = self.getRoot()
        #获取根节点下所有名叫book的节点对象
        books = self.findNodeByName(root,"book")
        dataList = []
        #遍历获取到的所有book节点对象,取得需要的测试数据
        for book in books:
            childrenText = self.getNodeOfChildText(book)
            dataList.append(childrenText)
        return dataList

if __name__ == "__main__":
    xml = ParseXML(r"D:\\PythonProject\\XMLDataDrivenProject\\TestData.xml")
    datas = xml.getDataFromXml()
    for i in datas:
        print i["name"],i["author"]

  DataDrivenByXml.py文件用于编写数据驱动测试脚本,具体内容如下:

#encoding=utf-8
from selenium import webdriver
import unittest,time,os
import logging,traceback
import ddt
from XmlUtil import ParseXML
from selenium.common.exceptions import NoSuchElementException

#初始化日志对象
logging.basicConfig(
    #日志级别
    level = logging.INFO,
    #日志格式
    #时间、代码所在文件名、代码行号、日志级别名、日志信息
    format = "%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s",
    #打印日志的时间
    datefmt = "%a,%d %b %Y %H: %M: %S",
    #日志文件存放的目录(目录必须存在)及日志文件名
    filename = "D:\\test\\DataDrivenTesting\\report.log",
    #打开日志文件的方式
    filemode = "w"
)

#获取当前文件所在父目录的绝对路径
currentPath = os.path.dirname(os.path.abspath(__file__))
#获取数据文件的绝对路径
dataFilePath = os.path.join(currentPath,"TestData.xml")
print dataFilePath

#创建ParseXML类实例对象
xml = ParseXML(dataFilePath)

@ddt.ddt
class TestDemo(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Ie(executable_path = "D:\\IEDriverServer")

    @ddt.data(*xml.getDataFromXml())
    def test_dataDrivenByXml(self,data):
        testdata,expectdata = data["name"],data["author"]
        url = "http://www.baidu.com"
        #访问百度首页
        self.driver.get(url)
        #将浏览器窗口最大化
        self.driver.maximize_window()
        print testdata,expectdata
        #设置隐式等待时间为10秒
        self.driver.implicitly_wait(10)

        try:
            #找到搜索输入框,并输入测试数据
            self.driver.find_element_by_id("kw").send_keys(testdata)
            #找到搜索按钮,并单击
            self.driver.find_element_by_id("su").click()
            time.sleep(3)
            #断言期望结果是否出现在页面源代码中
            self.assertTrue(expectdata in self.driver.page_source)
        except NoSuchElementException,e:
            logging.error(u"查找的页面元素不存在,异常堆栈信息:"+str(traceback.format_exc()))
        except AssertionError, e:
            #注意引号格式
            logging.info(u"搜索“%s”,期望“%s”,失败" % (testdata, expectdata))
        except Exception, e:
            logging.error(u"未知错误,错误信息:" + str(traceback.format_exc()))
        else:
            logging.info(u"搜索“%s”,期望“%s”,通过" % (testdata, expectdata))

    def tearDown(self):
        self.driver.quit()

if __name__ == "__main__":
    unittest.main()

7、使用MySQL数据库进行数据驱动测试
测试逻辑:
(1)打开百度首页,从MySql数据库中获取测试过程中需要的测试数据
(2)在搜索输入框中输入查询关键词测试数据
(3)单击搜索按钮
(4)断言搜索结果页面中是否出现数据库中提供的预期内容,包含则认为测试执行成功,否则认为失败
环境准备:
安装MySql

实例代码:
在PyCharm中新建一个名叫DataBaseDataDrivenProject的Python工程,并在工程下新建四个文件,文件名分别为Sql.py、DataBaseInit.py、MysqlUtil.py和DataDrivenByMySql.py
Sql.py文件用于编写创建数据库及数据表的Sql语句,具体内容如下:

#encoding=utf-8

# 创建gloryroad数据库sql语句
create_database = 'CREATE DATABASE IF NOT EXISTS gloryroad DEFAULT CHARSET utf8 COLLATE utf8_general_ci;'

# 创建testdata表
create_table = """
    drop table if exists testdata;
    create table testdata(
        id int not null auto_increment comment '主键',
        bookname varchar(40) unique not null comment '书名',
        author varchar(30) not null comment '作者',
        test_result varchar(30) default null,
        primary key(id)
    )engine=innodb character set utf8 comment '测试数据表';
"""

  DataBaseInit.py文件用于编写初始化数据库的脚本,具体内容如下:

#encoding=utf-8
import MySQLdb
from Sql import *

class DataBaseInit(object):
    # 本类用于完成初始化数据操作
    # 创建数据库,创建数据表,向表中插入测试数据
    def __init__(self, host, port, dbName, username, password, charset):
        self.host = host
        self.port = port
        self.db = dbName
        self.user = username
        self.passwd = password
        self.charset = charset

    def create(self):
        try:
            # 连接mysql数据库
            conn = MySQLdb.connect(
                host = self.host,
                port = self.port,
                user = self.user,
                passwd = self.passwd,
                charset = self.charset
            )
            # 获取数据库游标
            cur = conn.cursor()
            # 创建数据库
            cur.execute(create_database)
            # 选择创建好的gloryroad数据库
            conn.select_db("gloryroad")
            # 创建测试表
            cur.execute(create_table)
        except MySQLdb.Error, e:
            print e
        else:
            # 关闭游标
            cur.close()
            # 提交操作
            conn.commit()
            # 关闭连接
            conn.close()
            print u"创建数据库及表成功"

    def insertDatas(self):
        try:
            # 连接mysql数据库中具体某个库
            conn = MySQLdb.connect(
                host = self.host,
                port = self.port,
                db = self.db,
                user = self.user,
                passwd = self.passwd,
                charset = self.charset
            )
            cur = conn.cursor()
            # 向测试表中插入测试数据
            sql = "insert into testdata(bookname, author) values(%s, %s);"
            res = cur.executemany(sql, [('Selenium WebDriver实战宝典', '吴晓华'),
                                  ('HTTP权威指南', '古尔利'),
                                  ('探索式软件测试', '惠特克'),
                                  ('暗时间', '刘未鹏')])
        except MySQLdb.Error, e:
            raise e
        else:
            conn.commit()
            print u"初始数据插入成功"
            # 确认插入数据成功
            cur.execute("select * from testdata;")
            for i in cur.fetchall():
                print i[1], i[2]
            cur.close()
            conn.close()


if __name__ == '__main__':
    db = DataBaseInit(
        host="localhost",
        port=3306,
        dbName="gloryroad",
        username="root",
        password="123456",
        charset="utf8"
    )
    db.create()
    db.insertDatas()
    print u"数据库初始化结束"

  MysqlUtil.py文件用于从数据库中获取测试数据,具体内容如下:

#encoding=utf-8
import MySQLdb
from DataBaseInit import DataBaseInit

class MyMySQL(object):
    def __init__(self, host, port, dbName, username, password, charset):
        # 进行数据库初始化
        dbInit = DataBaseInit(host, port, dbName, username, password, charset)
        dbInit.create()
        dbInit.insertDatas()
        self.conn = MySQLdb.connect(
            host = host,
            port = port,
            db = dbName,
            user = username,
            passwd = password,
            charset = charset
        )
        self.cur = self.conn.cursor()

    def getDataFromDataBases(self):
        # 从testdata表中获取需要的测试数据
        # bookname作为搜索关键词,author作为预期关键词
        self.cur.execute("select bookname, author from testdata;")
        # 从查询区域取回所有查询结果
        datasTuple = self.cur.fetchall()
        return datasTuple

    def closeDatabase(self):
        # 数据库后期清理工作
        self.cur.close()
        self.conn.commit()
        self.conn.close()

if __name__ == '__main__':
    db = MyMySQL(
        host="localhost",
        port=3306,
        dbName="gloryroad",
        username="root",
        password="123456",
        charset="utf8"
    )
    print db.getDataFromDataBases()

  DataDrivenByMySQL.py文件用于编写数据驱动测试脚本代码,具体内容如下:

# encoding=utf-8
from selenium import webdriver
import unittest, time
import logging, traceback
import ddt
from MysqlUtil import MyMySQL
from selenium.common.exceptions import NoSuchElementException

# 初始化日志对象
logging.basicConfig(
    # 日志级别
    level = logging.INFO,
    # 日志格式
    # 时间、代码所在文件名、代码行号、日志级别名字、日志信息
    format = '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    # 打印日志的时间
    datefmt = '%a, %Y-%m-%d %H:%M:%S',
    # 日志文件存放的目录(目录必须存在)及日志文件名
    filename = 'D:\\test\\DataDrivenTesting\\report.log',
    # 打开日志文件的方式
    filemode = 'w'
)

def getTestDatas():
    db = MyMySQL(
        host="localhost",
        port=3306,
        dbName="gloryroad",
        username="root",
        password="123456",
        charset="utf8"
    )
    # 从数据库测试表中获取测试数据
    testData = db.getDataFromDataBases()
    # 关闭数据库连接
    db.closeDatabase()
    return testData

@ddt.ddt
class TestDemo(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Ie(executable_path = "D:\\IEDriverServer")

    @ddt.data(*getTestDatas())
    def test_dataDrivenByDatabase(self, data):
        # 对获得的数据进行解包
        testData, expectData = data
        url = "http://www.baidu.com"
        # 访问百度首页
        self.driver.get(url)
        # 将浏览器窗口最大化
        self.driver.maximize_window()
        print testData, expectData
        # 设置隐式等待时间为10秒
        self.driver.implicitly_wait(10)
        try:
            # 找到搜索输入框,并输入测试数据
            self.driver.find_element_by_id("kw").send_keys(testData)
            # 找到搜索按钮,并点击
            self.driver.find_element_by_id("su").click()
            time.sleep(3)
            # 断言期望结果是否出现在页面源代码中
            self.assertTrue(expectData in self.driver.page_source)
        except NoSuchElementException, e:
            logging.error(u"查找的页面元素不存在,异常堆栈信息:"\
                          + str(traceback.format_exc()))
        except AssertionError, e:
            logging.info(u"搜索“%s”,期望“%s”,失败" %(testData, expectData))
        except Exception, e:
            logging.error(u"未知错误,错误信息:" + str(traceback.format_exc()))
        else:
            logging.info(u"搜索“%s”,期望“%s”通过" %(testData, expectData))

    def tearDown(self):
        self.driver.quit()

if __name__ == '__main__':
    unittest.main()

 

推荐阅读