Python+Selenium自动化测试实践——PageObject篇(01)

网上现在有不少对于PageObject的说明和理解,可是从我看来,对待这种方式,每个人都有自己的理解方式,我自己其实也看了网上的一些介绍,但是说真的,有时候不是特别想去按照别人的思维方式来进行。不管别人的东西对不对。另外每个人的基础知识的储备不同,也让大家在对待一个问题的时候,理解的方向就会有所不同。那么作为个人,我的通俗非专业的理解如下:

  1. PO 模式 = pageobject
  2. PO 是一种通过不断分离数据(参数化),不断的分离出公用代码(模块化),不断的将业务和实现过程分离的一种非官方的一种方式。
  3. PO 是一种将page形成类和对象,统一管理的思路
    针对上面的自己个人理解和实际操作,这次介绍的是通过继承的方式来设计
    1. 首先介绍一下个人的代码文件夹结构和说明:

    关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
    image.png

如上图:
excel_doc : 该文件夹主要是用于存放execl的测试用例excel,以及针对与excel的一个py文件,用于对test用例的操作

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

log: 顾名思义,就是存放执行过程中的log日志,同时log的py文件也在其中
report:很好理解的一个东西,就是测试报告,通过htmltestrunner自动生成的
testcase: 该地方就是存储执行的用例的地方。

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

testproject:该地方主要就是存储baseclass ,以及对应的页面类

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

test_all_case: 测试执行的py文件

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

如上就是自己的测试用例文件夹目录,这东西不是固定的,其实个人感觉你完全可以根据自己的喜好来定义这个名称和目录,比如把page类,放在一个文件夹目录也是可以的,不用纠结与网上的各种目录结构。

整体设计思路如下:

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png
  1. 如何开展代码,从那里开始着手?
    这个地方我要说一下,其实这个完全看个人的代码编写能力,如果是代码老员工的话,那么直接就可以从整个case的外环境编写,比如baseMethod,commonMethod,test-all-caese等,如果是新人,个人建议从testcase来写。然后不断的去参数化,模块化。
    我就按照我的方式来说明一下,比较综合:
    第一步: 封装自己需要到的一些基础webdriver中需要的方法
    selenium自带的webdriver的什么定位,输入值等都已经够用了。但是为了让自己实际使用起来更加符合自己的想法,我们需要对其进行二次的封装和重写,当然这里说的好像很高大上,但是就我的能力来说,就是为了看起来稍微简洁一点:
    举例部分BaseMethodClass类方法:
# coding=utf-8
__author__ = 'Administrator'
from selenium import webdriver
import time
import os
# import xlrd
# import xlwt
from selenium.webdriver.support.ui import WebDriverWait
# from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.common.action_chains import ActionChains
class BaseMethodClass(object):
   """
       基础类方法、主要是用于写用户的基础操作函数,目前来说总的是对现在webdriver默认的函数进行改写
       变为更加易读的方式
   """
   # 设置需要的浏览器对象
   def set_browser(self, browser_name):
       if browser_name == 'chrome':
           self.browser = webdriver.Chrome()
       elif browser_name == "ie":
           self.browser = webdriver.Ie()
       elif browser_name == 'firefox':
           self.browser = webdriver.Firefox()
   # 退出该浏览器的下的对象
   def quit_browser(self):
       self.browser.quit()
   # 关闭浏览器
   def close_browser(self):
       self.browser.close()
   # 打开指定的网页并且最大化
   def open_web_and_maxsize(self, url):
       self.browser.get(url)
       self.browser.maximize_window()
   # 定位一个元素
   def find_element(self, type_name, location):
       try:
           if type_name == 'id':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_id(location))
               return ele
               # return self.browser.find_element_by_id(location)
           elif type_name == 'css':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_css_selector(location))
               return ele
               # return self.browser.find_element_by_css_selector(location)
           elif type_name == 'xpath':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_xpath(location))
               return ele
               # return self.browser.find_element_by_xpath(location)
           elif type_name == 'classname':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_class_name(location))
               return ele
               # return self.browser.find_element_by_class_name(location)
           elif type_name == 'name':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_name(location))
               return ele
               # return self.browser.find_element_by_name(location)
           elif type_name == 'tagname':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_tag_name(location))
               return ele
               # return self.browser.find_element_by_tag_name(location)
           elif type_name == 'part_linktext':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_partial_link_text(location))
               return ele
               # return self.browser.find_element_by_partial_link_text(location)
           elif type_name == 'linktext':
               ele = WebDriverWait(self.browser, 10).until(
                   lambda browser: browser.find_element_by_link_text(location))
               return ele
               # return self.browser.find_element_by_link_text(location)
       except:
           print u"没有找到该 %s 元素位置:%s" % (type_name, location)

如上代码,base类中对于定位元素和退出浏览器等方法都进行了改装
CommonMethod模块
主要是写一些,例如邮件发送,找到case,生成报告文件等

# coding=utf-8
import smtplib
__author__ = 'Administrator'
import os
from BaseMethod import BaseMethodClass
import unittest
from email.mime.text import MIMEText
from email.header import Header
import time
# 函数用到的数据
# report_path_1 = os.path.abspath(os.path.join(os.getcwd(), '..\report'))
report_path_1 = "C:\Python27\workspace\study\JC_autotest\qhddfxlPO\report"
"""从file_path文件夹中,筛选出所有的case,并且存放到testsuite套件中"""
def find_all_case_1(file_path):
    # 创建一个套件: 可理解为准备一个大袋子,用来装case这个苹果
    test_suites = unittest.TestSuite()
    # 发现了所有的case苹果,但是很乱
    discover_case = unittest.defaultTestLoader.discover(file_path,
                                                        pattern='test1*.py',
                                                        top_level_dir=None)
    # 将上面的未包装的苹果case统一放入到大袋子中
    for test_suite in discover_case:
        for test_case in test_suite:
            test_suites.addTest(test_case)
    # 返回这个袋子苹果
    return test_suites
"""从report文件夹中读取最新的一个测试报告"""
def find_newest_report_1(report_path):
    # 获得path下的所有文件
    # report_path = report_path_1
    lists = os.listdir(report_path)
    # print 'List1:', lists
    # 对当前文件夹下的所有文件进行排序
    lists.sort(key=lambda fx: os.path.getctime(report_path + "\" + fx))
    # print 'List2:', lists
    report = lists[-1]
    # 返回当前最新的一个文件
    newest_report = os.path.join(report_path, report)
    return newest_report
"""不带附件的邮件"""
def send_mail_2(receiver_user, receiver_pwd):
    # 发送者邮箱
    sender = "wy956486535@126.com"
    # 接受者邮箱
    receiver = receiver_user
    # 通过XXsmtp的服务器
    smtpserver = 'smtp.126.com'
    # 发送邮件中的主题
    email_subject = u'XXXXX项目自动化测试运行报告'
    # 发送邮件中的内容
    email_content = find_newest_report_1(report_path_1)
    # 发送邮箱需要指定人员的授权名称和密码
    grant_person = receiver_user
    grant_pwd = receiver_pwds
    # 将或者的邮件内容转换成可读取状态
    fp1 = file(email_content, 'rb')
    content = fp1.read()
    # msg = email.MIMEText(content, _charset='utf-8', _subtype='html')
    msg = MIMEText(content, _charset="utf-8", _subtype="html")
    msg["subject"] = Header(email_subject, "utf-8")
    # 发送邮件
    smtp = smtplib.SMTP()
    smtp.connect(smtpserver)
    smtp.login(grant_person, grant_pwd)
    smtp.sendmail(sender, receiver, msg.as_string())
    smtp.quit()
"""生成动态时间测试报告"""
def makeA_report_1(reportpath):
    now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time()))
    # reportpath1 = os.path.abspath(os.path.join(os.getcwd(), '..\report'))
    report_path = reportpath + '\' + now + "-" + "report.html"
    report_file = file(report_path, 'wb')
    return report_file

第二步:通过继承Base类,对Page页面中的功能进行封装

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

第三步:通过继承page类,进行页面的case设计,

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

由于通过是不断的继承,所以在后期的代码效果就是

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

对于case的管理,目前也有两方方式:

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

每个py文件就一个case(优点是,并且每个case都是通过py文件独立,互相之间影响小 ,但是对于系统测试点详细的时候,会出现大量的py文件,不适合后期管理,个人觉得比较适合那种关于流程性的case)

关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)关于自动化Python+Selenium的自动化测试实践——之PageObject篇(01)
image.png

一个py文件中,执行多个case,(优点是生成的py文件少,一个py中就可以实现多case,比较好管理,缺点是,这种方式如果后期需要公用一个driver的时候,就比较难理解)

第四步:case完成后,就可以对testcase的执行执行设计,如下:

# coding=utf-8
__author__ = 'Administrator'
from testproject1.CommonMethod import *
from study.JC_autotest.qhddfxlPO.log import log
import HTMLTestRunner
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
# import unittest
if __name__ == "__main__":
    title = u"青海电大测试报告"
    description = u"青海电大测试"
    file_path = "C:\Python27\workspace\study\JC_autotest\qhddfxlPO\testcase1"
    rep = makeA_report_1("C:\Python27\workspace\study\JC_autotest\qhddfxlPO\report")
    runner = HTMLTestRunner.HTMLTestRunner(
        stream=rep,
        title=title,
        description=description
    )
    # runner = unittest.TextTestRunner()
    all_testcases = find_all_case_1(file_path)
    runner.run(all_testcases)
    # 如果这个没有,那么就会出现在htmltestrunner执行的报告中写入的报告不全的情况
    rep.close()
    send_mail_2("wxxxxx@126.com", "wyxxxxx35")

上图中的,find_all_case 和 makeA_report 都是在commonmethod中的封装的方法,此处通过导入后,直接调用的

综上所属,基本上一个简单的通过继承关系得到的po就出来了。

个人感觉这个po的方便在于不管是Base类中的方法,还是page类中的方法,,都可以在你实现自己的case的业务脚本中调用,不会让你在case中,因为page未有对应的业务方法而去在page中去特意封装一个和base类一样的方法
但是也有人对这种的存在疑问: 因为case和page并不存在is a 这种子父类的关系,从某一方面来说这种设计是不合理的,但是有时候一个阶段,自己就会有一个阶段的自我认识,而当时我的思路就是这样的。

       

留言

本站文章如未特殊注明,均为原创,转载请注明出处: 未必平凡  本文链接地址: https://vv2014.com/1254.html