一种基于Python 语言自动化测试框架的实现
作者: 刘玮玮
摘要:文章通过设计特定测试场景,编写测试用例数据,基于Python的Unittest框架,采用PO模式实现通用操作封装,使用ddt装饰器实现遍历测试数据并批量执行。所实现的自动化测试检验了人力资源管理系统中,以系统管理员身份登录时,添加政治类别操作可能出现的几种情况。该测试过程能够自动截图,并通过断言比较测试用例的正确性,同时将生成的测试报告发送到指定邮箱。
关键词:Python;Unittest框架;PO对象;ddt装饰器;自动化测试
中图分类号:TP311.53 文献标识码:A
文章编号:1009-3044(2024)17-0055-04 开放科学(资源服务)标识码(OSID) :
0 引言
作为保证软件质量的重要手段,软件测试在日新月异的软件开发中愈发重要。自动化测试是将以人为驱动的测试行为转化为机器执行的过程,即模拟手工测试步骤,通过执行以程序语言编制的测试脚本自动地测试软件,涵盖了所有测试阶段。自动化测试具有跨平台兼容性,且与进程无关。广义的自动化测试强调整个测试过程都由计算机系统完成,范围更广;狭义的自动化测试主要指通过某个自动化工具自动执行特定测试任务,处理范围较小。
自动化测试适用于回归测试,因为重复单一的数据录入或击键等测试操作会造成不必要的时间和人力浪费。测试人员通常需要借助自动化测试工具对程序进行理解和对设计文档进行验证。采用自动化测试工具还有利于生成测试报告文档,保持版本的连贯性。自动化工具也能够确定测试用例的覆盖路径,确定测试用例集对程序逻辑流程和控制流程的覆盖。本文以系统管理员身份登录人资管理系统,验证添加政治面貌类别操作。
1 Unittest 框架
Unittest框架是Python自带的一种单元测试框架,具备编写用例、组织用例、执行用例、输出报告等自动化框架的条件。该框架可以实现批量执行用例,提供丰富的断言知识,还可以生成报告。Unittest框架的核心要素包括:TestCase(测试用例),TestSuite(测试套件),TextTestRunner(以文本形式运行测试用例),Tes⁃tLoader(批量执行测试用例-搜索指定文件夹内指定字母开头的模块),Fixture(固定装置(两个固定的函数,一个初始化时使用,一个结束时使用)) 。在使用Unittest框架创建测试用例时,首先要导入unittest包,新建的测试类需继承unittest.TestCase,并且测试方法必须以test字母开头[1]。
2 具体实现
2.1 测试环境搭建
安装Python、Selenium 插件、PyCharm 平台,配置相关环境变量后,还需要安装Chrome浏览器及对应Chrome驱动,并确保可以成功登录打开人资管理系统。打开PyCharm平台,创建一个项目,同时在创建项目时选择解释器为当前安装的Python[2]。
测试数据准备如图1所示。
项目路径如图2所示[3]。
2.2 封装基本操作
首先在指定名称文件夹下创建driver.py文件,封装打开谷歌浏览器操作,代码如下:
from selenium import webdriver
def browser():
driver=webdriver.Chrome()
#打开谷歌浏览器
return driver
在指定文件夹下创建function.py文件[4],封装截图方法inser_img(driver,filename),查找最新测试报告方法latest_report(report_dir),将测试报告发送到邮箱的方法send_mail(latest_report),以及读取csv文件方法。读取csv文件方法可以通过逐行逐列循环读取csv文件来批量执行测试用例,即通过数据驱动实现自动化测试某个功能,读取csv文件代码如下:
def get_csv_file(line):
# 文件路径需要自己修改成自己的文件路径
with open(r"盘符:\*\*\需被读取的文件名.csv",encoding=′utf-8-sig′) as file:
reader=csv.reader(file)
for index,row in enumerate(reader,1):
if index==line:
return row 以及创建myunit.py文件,封装启动测试集和结束测试集操作,代码如下:
import unittest
from driver.driver import *
class StartEnd(unittest.TestCase):
def setUp(self):
self.driver=browser()
self.driver.implicitly_wait(10)
self.driver.maximize_window()
def tearDown(self):
self.driver.quit()
2.3 定义基础类Python 文件
创建基础类BasePage.py,用于被所有页面对象类继承。其中,初始化方法用于打开被测系统页面,open方法用于打开指定url地址页面,find_element方法用于查找指定页面元素,相关代码如下:
from time import sleep
class Page():
def __init__(self, driver):
self.driver = driver
self. base_url = ′http://116.204.108.152: 30016/suthr/logon′
def _open(self, url):
url_ = self.base_url + url
print("Test page is %s" % url_)
self.driver.maximize_window()
self.driver.get(url_)
sleep(2)
assert self.driver.current_url == url_, ′Did not land on %s′ % url_
def open(self):
self._open(self.url)
def find_element(self, *loc):
return self.driver.find_element(*loc)
2.4 创建PageObject 对象
创建PO对象LoginPage.py文件,用于封装登录人资系统的操作;AddLeibiePage.py文件用于封装一系列操作,包括点击系统管理员链接→输入系统管理员用户名→输入系统管理员密码→点击登录按钮→点击类别维护菜单→点击政治面貌类别子菜单→点击创建类别按钮→填写政治类别名称框→填写描述框→点击保存按钮,以及读取弹窗文字信息和红底提示文字信息等。
以输入政治类别名称,点击保存为例,代码如下:
from selenium.webdriver.common.by import By
from Website. test_case. page_object. BasePage im⁃port *
from time import sleep
class LeibieAdd(Page):
...
lbmc = (By.ID, ′dictValue′) # 定位类别名称输入框
Baocun_loc = (By.XPATH, ′//*[@id="ajax-modal"]/div[3]/button[1]′) # 定位保存按钮hongdi_loc = (By.ID,′dictValue-error′) # 定位消息提示文字信息
...
def type_lbmc(self, lbname):
self.find_element(*self.lbmc).clear()
self.find_element(*self.lbmc).send_keys(lbname)
# 输入类别名称
def type_Baocun(self):
self.find_element(*self.Baocun_loc).click()
#点击保存按钮
def type_hongdi(self):
return self.find_element(*self.hongdi_loc).get_attri⁃bute("innerHTML")
# 读取红底文字信息
...
def test_zzlb_add(driver, lbname):
...
sleep(1)
add_page.type_lbmc(lbname)
sleep(1)
add_page.type_Baocun()
需要注意的是,各类动态增加方法时一定要加self参数,并且PO类与调用PO类的封装方法缩进要一致,表示同级的关系。如果缩进不一致,在后续测试类调用封装方法时会报“方法没有定义”的错误。
2.5 创建测试类
使用unittest框架创建测试类test_addzz.py,测试类中每一个以test开头的方法就是一条测试用例。同时,使用ddt装饰器实现遍历测试数据,每遍历出一条数据,就往测试类中添加一个以test开头的方法setattr (类,方法名,方法)[5]。
该测试类通过调用function.py中的读取csv文件方法get_csv_file(line)以及调用test_user_login(driver,username,password)方法,分别测试了csv文件中的3条测试数据,对应添加政治类别中的输入政治类别名称为空、重复和过长的操作。测试类能够实现测试界面的截屏,并且能够断言对比测试用例是否正确。关键代码如下:
import unittest
from Website. test_case. model import function,myunit
from Website.test_case.page_object.AddLeibiePage import *
from Website.test_case.page_object.LoginPage im⁃port *
from Website. test_case. page_object. AddPage im⁃port *
import time
import ddt