使用PageObject改造Macaca示例(桌面端)

在学习完Macaca基础后,就迫不及待的模仿着Macaca示例项目,开始了测试用例的开发,并且在几天时间里就完成了几个页面的测试。然而,此时项目的所有代码都放在一个.py文件里,该文件已有上千行代码,重复代码很多,维护起来非常困难。

为了避免这种情况发生,可以使用PageObject设计模式开发Macaca项目。Page Object是自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装,减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高了测试用例的可维护性。

以Macaca的桌面端示例代码为例,按它的模式继续写,肯定会出现前面说的情况,大量的重复代码,而且无法维护。但是如果把Macaca的桌面端示例改造成PageObject设计模式,就能减少重复代码,提高可维护性。

项目目录结构

首先,先建立一个下图所示的项目目录结构:

使用PageObject改造Macaca示例(桌面端)_第1张图片
项目目录结构

如上图,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生成的测试报告。

使用PageObject改造Macaca示例(桌面端)_第2张图片
HTMLTestRunner与HTMLTestRunnerCN

如上图所示,HTMLTestRunner的UI样式并不是很好看,而且对中文的支持不好。但是你还可以选择使用HTMLTestRunnerCN生成测试报告,这是在HTMLTestRunner.py的基础上进行了修改定制的版本,打开HTMLTestRunnerCN网站下载HTMLTestRunnerCN.py文件,放在.../mail/report/template文件夹下。

你可能感兴趣的:(使用PageObject改造Macaca示例(桌面端))