美文网首页
使用PageObject改造Macaca示例(桌面端)

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

作者: 何小有 | 来源:发表于2018-01-08 10:40 被阅读66次

    在学习完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'] = 'abc@yeah.net'
        # 设置收件人
        msg['To'] = 'def@qq.com'
        # 实例化Smtplib模块的SMTP对象来连接到SMTP访问
        smtp = smtplib.SMTP()
        # 连接SMTP服务器
        smtp.connect('smtp.yeah.net')
        # 登录邮箱账号
        smtp.login('abc', '123456')
        # 发送邮件
        smtp.sendmail('abc@yeah.net', 'def@qq.com', 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与HTMLTestRunnerCN

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

    相关文章

      网友评论

          本文标题:使用PageObject改造Macaca示例(桌面端)

          本文链接:https://www.haomeiwen.com/subject/jxednxtx.html