在学习完Macaca基础后,就迫不及待的模仿着Macaca示例项目,开始了测试用例的开发,并且在几天时间里就完成了几个页面的测试。然而,此时项目的所有代码都放在一个.py文件里,该文件已有上千行代码,重复代码很多,维护起来非常困难。
为了避免这种情况发生,可以使用PageObject设计模式开发Macaca项目。Page Object是自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装,减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高了测试用例的可维护性。
以Macaca的桌面端示例代码为例,按它的模式继续写,肯定会出现前面说的情况,大量的重复代码,而且无法维护。但是如果把Macaca的桌面端示例改造成PageObject设计模式,就能减少重复代码,提高可维护性。
项目目录结构
首先,先建立一个下图所示的项目目录结构:
如上图,page_object是测试项目的名称,在它下面有driver和mail两个文件夹,其中driver是用于存放驱动,mail用于存放项目的测试用例、测试报告以及测试数据等,同目录下还有run_all_test.py文件,用于运行项目的所有自动化用例。
在mail文件夹下,有data、report、test_case三个文件夹,其中data用于存放测试数据,report用于存放测试报告,test_case用于存放测试用例。
在report文件夹下,有image和template两个文件夹,其中image用于存放测试过程中的截图,template用于存放生成测试报告的工具。
在test_case文件夹下,有model和page_object两个文件夹,其中model用于存放配置函数及公共类,page_object用于存放页面对象,同目录下还有search_case.py这个测试对象用例。
编写公共模块
在.../mail/test_case/model文件夹下新建driver.py文件,编写公共驱动文件:
# -*- coding:utf-8 -*-
from macaca import WebDriver
# 启动浏览器驱动
def browser():
desired_caps = {
'platformName': 'desktop',
'browserName': 'electron'
}
server_url = 'http://localhost:3456/wd/hub'
driver = WebDriver(desired_caps, server_url)
return driver
在.../mail/test_case/model文件夹下新建function.py文件,编写公共函数文件:
# -*- coding:utf-8 -*-
import os
# 截图函数
def insert_img(driver, file_name):
# 获取当前文件所在的父级目录,其中__file__为当前文件的绝对路径
base_dir = os.path.dirname(__file__)
# 获取当前目录所在的父级目录
base_dir = os.path.dirname(base_dir)
# 将当前目录进行切片操作,其中[-1]是指列表的最后一个元素
base = base_dir.split('/mail')[0]
# 将多个路径组合成截图存放路径
file_path = base + '/mail/report/image/' + file_name
# 将截图保存到本地
driver.save_screenshot(file_path)
在.../mail/test_case/model文件夹下新建myunit.py文件,编写公共测试类文件:
# -*- coding:utf-8 -*-
import unittest
from driver import browser
class MyTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = browser()
cls.driver.init()
@classmethod
def tearDownClass(cls):
cls.driver.quit()
编写页面对象
在.../mail/test_case/page_object文件夹下新建base.py文件,编写基础类文件:
# -*- coding:utf-8 -*-
class Base(object):
"""
基本层
"""
def __init__(self, driver):
self.driver = driver
def open(self, url='https://www.baidu.com'):
"""
在当前浏览器会话中加载Web页面
:param url: 导航到的URL
:return: WebDriver对象
"""
self.driver.set_window_size(1280, 800)
self.driver.get(url)
def source(self):
"""
获取当前页面的源代码
:return: 页面的源代码
"""
return self.driver.source
def id(self, _id):
"""
通过ID查找元素
:param _id: 元素的ID
:return: WebElement对象
"""
return self.driver.element_by_id(_id)
def xpath_or_none(self, xpath):
"""
通过XMLPath查找元素
:param xpath: 元素的XMLPath
:return: 如果元素存在,返回WebElement对象,否则返回None
"""
return self.driver.element_by_xpath_or_none(xpath)
def css_selector_if_exists(self, css_selector):
"""
通过CSS选择器判断元素是否存在
:param css_selector: 元素的CSS选择器
:return: 如果元素存在,返回True,否则返回False
"""
return self.driver.element_by_css_selector_if_exists(css_selector)
在.../mail/test_case/page_object文件夹下新建search_page.py文件,编写搜索页面对象类文件:
# -*- coding:utf-8 -*-
from base import Base
class SearchPage(Base):
"""
页面对象(PO): 搜索页面
"""
# 搜索框ID
search_input_loc = 'kw'
# 搜索按钮ID
search_button_loc = 'su'
def search_input(self, text):
"""
在搜索框输入文本
:param text: 输入文本
:return: None
"""
self.id(self.search_input_loc).send_keys(text)
def search_button(self):
"""
点击搜索按钮
:return: None
"""
self.id(self.search_button_loc).click()
在.../mail/test_case/page_object文件夹下新建search_result_page.py文件,编写搜索结果页面对象类文件:
# -*- coding:utf-8 -*-
from base import Base
class SearchResultPage(Base):
"""
页面对象(PO): 搜索结果页面
"""
# 搜索框XPath
search_input_loc = '//*[@id="kw"]'
# 搜索按钮ID
search_button_loc = 'su'
def search_input(self, text):
"""
在搜索框输入文本
:param text: 输入文本
:return: None
"""
self.xpath_or_none(self.search_input_loc).send_keys(text)
def search_button(self):
"""
点击搜索按钮
:return: None
"""
self.id(self.search_button_loc).click()
编写测试用例
在.../mail/test_case文件夹下新建search_case.py文件,编写搜索用例类文件:
# -*- coding:utf-8 -*-
import myunit
import function
from search_page import SearchPage
from search_result_page import SearchResultPage
from time import sleep
class SearchTest(myunit.MyTest):
"""百度搜索测试"""
def test_get_url(self):
"""打开百度的Web页面"""
search_po = SearchPage(self.driver)
search_po.open()
def test_search_keyword(self):
"""搜索关键词PageObject"""
search_po = SearchPage(self.driver)
search_po.search_input('PageObject')
search_po.search_button()
sleep(3)
search_result_po = SearchResultPage(self.driver)
html = search_result_po.source()
self.assertTrue('PageObject' in html)
self.assertTrue(
search_result_po.css_selector_if_exists('#head > div.head_wrapper')
)
search_result_po.search_input(' 设计模式')
search_result_po.search_button()
function.insert_img(self.driver, '完成.jpg')
执行测试用例
在项目根目录下新建search_case.py文件,编写用例执行代码文件:
# -*- coding:utf-8 -*-
import unittest
import time
import os
import smtplib
from HTMLTestRunnerCN import HTMLTestRunner
from email.mime.text import MIMEText
from email.header import Header
# 发送测试报告到指定邮箱账号
def send_mail(file_new):
# 打开一个文件,读取测试报告
f = open(file_new, 'rb')
# 从文件读取所有的字节数
mail_body = f.read()
# 关闭文件
f.close()
# 新建HTML形式的邮件
msg = MIMEText(mail_body, 'html', 'utf-8')
# 设置邮件主题
msg['Subject'] = Header("自动化测试报告", 'utf-8')
# 设置发件人
msg['From'] = '[email protected]'
# 设置收件人
msg['To'] = '[email protected]'
# 实例化Smtplib模块的SMTP对象来连接到SMTP访问
smtp = smtplib.SMTP()
# 连接SMTP服务器
smtp.connect('smtp.yeah.net')
# 登录邮箱账号
smtp.login('abc', '123456')
# 发送邮件
smtp.sendmail('[email protected]', '[email protected]', msg.as_string())
# 结束SMTP访问
smtp.quit()
print('电子邮件发送成功!')
# 查找测试报告目录,找到最新生成的测试报告文件
def new_report(_test_report):
# 获取指定文件夹包含的文件或文件夹名字的列表
lists = os.listdir(_test_report)
# 将多个路径组合后返回,其中[-1]是指列表的最后一个元素
file_new = os.path.join(_test_report, lists[-1])
# 返回测试报告的路径
return file_new
# HtmlTestRunner生成测试报告的路径
test_report = '/Users/hekaiyou/PycharmProjects/page_object/mail/report'
# 指定测试用例为当前文件夹下的test_case目录
test_dir = './mail/test_case'
# 自动根据测试目录匹配查找测试用例文件,并将查找到的测试用例组装到测试套件
discover = unittest.defaultTestLoader.discover(test_dir, pattern = '*_case.py')
if __name__ == "__main__":
# 获取时间并转换为特定格式
now = time.strftime("%Y-%m-%d %H_%M_%S")
# 组成测试报告的绝对路径
filename = test_report+'/'+now+'报告.html'
# 打开一个文件,写入测试报告
fp = open(filename, 'wb')
# 生成测试报告
runner = HTMLTestRunner(stream=fp, title='自动化测试报告', description='测试用例描述', tester='测试人员')
# 执行找到的测试套件
runner.run(discover)
# 关闭文件
fp.close()
'''
# 发送邮件
new_report = new_report(test_report)
# 发送测试报告到邮箱
send_mail(new_report)
'''
生成测试报告
Python自动化脚本可以使用HTMLTestRunner生成测试报告,打开HTMLTestRunner网站下载HTMLTestRunner.py文件,放在.../mail/report/template文件夹下。通过sample_test_report.html文件可以预览一下HTMLTestRunner生成的测试报告。
如上图所示,HTMLTestRunner的UI样式并不是很好看,而且对中文的支持不好。但是你还可以选择使用HTMLTestRunnerCN生成测试报告,这是在HTMLTestRunner.py的基础上进行了修改定制的版本,打开HTMLTestRunnerCN网站下载HTMLTestRunnerCN.py文件,放在.../mail/report/template文件夹下。