欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一个基于POM模式的Web自动化测试框架

程序员文章站 2022-07-14 08:39:10
...

基于最近可能工作要求,和自动化脚本效率的问题上,对设计模式进行了一些了解

所以参考性的编写了一个这样的POM模式的Web自动化测试框架

如果大家有需要,可以看看,指导探讨一下

 

整体的文件目录

一个基于POM模式的Web自动化测试框架

设置了公共文档的读出,在config.ini

可以把一下公共的东西,如url,账号等放进去

一个基于POM模式的Web自动化测试框架

 

 

  1. 对公共类进行了封装 为Common中basePage包
class BasePage:
    """测试基类"""
    def __init__(self, driver):
        self.driver = driver

    def get_img(self):
        """截图"""
        # img文件夹路径
        img_path = os.path.join(test_123.getcwd.get_cwd(), 'img/')
        # img文件夹不存在,新建该文件夹
        if not os.path.exists(img_path):
            os.makedirs(img_path)
        # 获取当前日期
        local_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
        # 日期文件夹路径
        date_file_path = os.path.join(img_path,local_date)
        # 日期文件夹不存在,新建该文件夹
        if not os.path.exists(date_file_path):
            os.makedirs(date_file_path)
        # 截图存放路径
        local_time = time.strftime('%Y-%m-%d %H%M%S', time.localtime(time.time()))
        jt_name = local_time+'.png'
        jt_path = os.path.join(date_file_path, jt_name)
        try:
            self.driver.get_screenshot_as_file(jt_path)
            log1.info('截图保存成功')
        except BaseException:
            log1.error('截图失败', exc_info=1)
        print('Screenshot_Path:', jt_path)




    def open_browser(self):
        """打开浏览器,访问url"""
        browser = config.config_read('environment', 'browser')
        log1.info('读取浏览器配置,值为%s' % browser)
        url = config.config_read('environment', 'url')
        log1.info('读取url,值为%s' % url)
        # noinspection PyBroadException
        try:
            if browser == 'chrome':
                option = webdriver.ChromeOptions()
                option.add_argument('disable-infobars')
                self.driver = webdriver.Chrome(chrome_options=option)
                log1.info('打开chrome浏览器')
            elif browser == 'firefox':
                self.driver = webdriver.Firefox()
                log1.info('打开firefox浏览器')
            else:
                log1.error('浏览器配置有误,应为chrome或firefox')
            self.driver.get(url)
            log1.info('访问url')
            self.driver.maximize_window()
            log1.info('浏览器最大化')
            self.driver.implicitly_wait(10)
            log1.info('设置静态等待时间10秒')
            return self.driver
        except BaseException:
            log1.error('浏览器打开报错', exc_info=1)

    def get_element(self, selector):
        """定位元素"""
        by = selector[0]
        value = selector[1]
        bys = ['id', 'name', 'class', 'tag', 'link', 'plink', 'css', 'xpath']
        element = None
        if by in bys:
            try:
                if by == 'id':
                    element = self.driver.find_element_by_id(value)
                elif by == 'name':
                    element = self.driver.find_element_by_name(value)
                elif by == 'class':
                    element = self.driver.find_element_by_class_name(value)
                elif by == 'tag':
                    element = self.driver.find_element_by_tag_name(value)
                elif by == 'link':
                    element = self.driver.find_element_by_link_text(value)
                elif by == 'plink':
                    element = self.driver.find_element_by_partial_link_text(value)
                elif by == 'css':
                    element = self.driver.find_element_by_css_selector(value)
                elif by == 'xpath':
                    element = self.driver.find_element_by_xpath(value)
                log1.info('元素定位成功。定位方式:%s,使用的值:%s' % (by, value))
                return element
            except NoSuchElementException:
                log1.error('没有定位到元素,定位方式:%s,使用的值:%s' % (by, value), exc_info=1)
        else:
            log1.error('元素定位方式错误,请使用id,name,class,tag,link,plink,css,xpath为定位方式参数')

    @staticmethod
    def isdisplayed(element):
        """元素是否存在"""
        value = element.is_displayed()
        return value

    def type(self, selector, value):
        """往输入框输入内容"""
        element = self.get_element(selector)
        element.clear()
        # noinspection PyBroadException
        try:
            element.send_keys(value)
            log1.info('输入的内容:%s' % value)
        except BaseException:
            log1.error('内容输入报错', exc_info=1)
            self.get_img()

    def click(self, selector):
        """点击元素"""
        element = self.get_element(selector)
        # noinspection PyBroadException
        try:
            element.click()
            log1.info('点击元素成功')
        except BaseException:
            isdisplay = self.isdisplayed(element)
            if isdisplay is True:
                self.my_sleep(3)
                element.click()
                log1.info('点击元素成功')
            else:
                log1.error('点击元素报错', exc_info=1)

    @staticmethod
    def my_sleep(secondes):
        """强制等待"""
        time.sleep(secondes)
        log1.info('强制等待%d秒' % secondes)

    def get_title(self):
        """获取title"""
        title = self.driver.title
        log1.info('当前打开的title是:%s' % title)
        return title

    def get_text(self, selector):
        """获取text"""
        element = self.get_element(selector)
        text = element.text
        log1.info("获取的text:%s" % text)
        return text

    def use_js(self, js):
        """调用js"""
        # noinspection PyBroadException
        try:
            self.driver.execute_script(js)
            log1.info('js执行成功,js内容为:%s' % js)
        except BaseException:
            log1.error('js执行报错', exc_info=1)

    def switch_menue(self, parentelement, secelement, targetelement):
        """三级菜单切换"""
        self.my_sleep(3)
        # noinspection PyBroadException
        try:
            self.driver.switch_to_default_content()
            self.click(parentelement)
            log1.info('成功点击一级菜单:%s' % parentelement)
            self.click(secelement)
            log1.info('成功点击二级菜单:%s' % secelement)
            self.click(targetelement)
            log1.info('成功点击三级菜单:%s' % targetelement)
        except BaseException:
            log1.error('切换菜单报错', exc_info=1)

    def switch_ifarme(self, selector):
        """切换farm"""
        element = self.get_element(selector)
        # noinspection PyBroadException
        try:
            self.driver.switch_to.frame(element)
            log1.info('切换frame成功')
        except BaseException:
            log1.error('切换frame报错', exc_info=1)

    def get_handle(self):
        """获得当前handle"""
        handle = self.driver.current_window_handle
        return handle

    def chage_handle(self, handle):
        """切换窗口"""
        handles = self.driver.window_handles
        for i in handles:
            if i != handle:
                self.driver.switch_to_window(i)

    def dr_quit(self):
        self.driver.quit()

2.对LOG日志类也进行封装log.py

def get_log(logger_name):
    # 获取项目的根目录
    project_path = test_123.getcwd.get_cwd()
    Logs_path = os.path.join(project_path, 'Logs')
    # 获取本地时间,转为年-月-日格式
    local_date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
    # 日期文件夹路径
    date_file_path = os.path.join(Logs_path, local_date)
    # 如果没有日期文件夹,创建该文件夹
    if not os.path.exists(date_file_path):
        os.makedirs(date_file_path)
    # 完整日志存放路径
    all_log_path = os.path.join(date_file_path, 'All_Logs/')
    # 如果没有完整日志文件夹,创建该文件夹
    if not os.path.exists(all_log_path):
        os.makedirs(all_log_path)
    # 错误日志存放路径
    error_log_path = os.path.join(date_file_path, 'Error_Logs/')
    # 如果没有错误日志文件夹,创建该文件夹
    if not os.path.exists(error_log_path):
        os.makedirs(error_log_path)
    # 获取本地时间,转为年月日时分秒格式
    local_time = time.strftime('%Y-%m-%d %H%M%S', time.localtime(time.time()))
    # 设置日志文件名
    all_log_name = all_log_path + local_time + '.log'
    error_log_name = error_log_path + local_time + '.log'

    # 创建一个logger
    logger = logging.getLogger(logger_name)
    logger.setLevel(logging.INFO)

    # 创建handler
    # 创建一个handler写入所有日志
    fh = logging.FileHandler(all_log_name)
    fh.setLevel(logging.INFO)
    # 创建一个handler写入错误日志
    eh = logging.FileHandler(error_log_name)
    eh.setLevel(logging.ERROR)
    # 创建一个handler输出到控制台
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)

    # 定义日志输出格式
    # 以时间-日志器名称-日志级别-日志内容的形式展示
    all_log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    # 以时间-日志器名称-日志级别-文件名-函数行号-错误内容
    error_log_formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(module)s  - %(lineno)s - %(message)s')
    # 将定义好的输出形式添加到handler
    fh.setFormatter(all_log_formatter)
    ch.setFormatter(all_log_formatter)
    eh.setFormatter(error_log_formatter)

    # 给logger添加handler
    logger.addHandler(fh)
    logger.addHandler(eh)
    logger.addHandler(ch)
    return logger


log1 = get_log('selenium')

3.POM下简单的元素界面

from test_123.Common.basePage import BasePage



class HomePage(BasePage):
    """51"""


    qydl = ['id', 'qydl']
    txtent_userName=['id', 'txtent_userName']
    txtent_userPwd=['id','txtent_userPwd']
    imgbtnuserLogin=['id','imgbtnuserLogin']
    spanError=['id','spanError']



    def login_click(self, value):
        """输入账号"""
        self.click(self.qydl)
        self.click(self.txtent_userName)
        self.type(self.txtent_userName,value)


    def login1_click(self, value):
        '''输入密码'''
        self.click(self.txtent_userPwd)
        self.type(self.txtent_userPwd,value)
        self.click(self.imgbtnuserLogin)
        ssf=self.get_text(self.spanError)
        print(ssf)

4.测试集合的用例管理

 

import unittest
from test_123.Common.basePage import BasePage
from test_123.PageObject.homePage import HomePage
from test_123.Common.log import log1
from test_123.Common.HTMLTestRunner import *



class TestHome(unittest.TestCase):
    """测试主页面"""

    def setUp(self):
        browser = BasePage(self)
        self.driver = browser.open_browser()

    def test_login(self):
        """测试搜索"""
        case_name = '测试搜索'
        log1.info("执行测试用例:%s" % case_name)
        home = HomePage(self.driver)
        home.my_sleep(2)
        title=home.login_click('123456')
        title1=home.login1_click('123456')





    def tearDown(self):
        home = HomePage(self.driver)
        home.dr_quit()

5.对用例进行集合输出报告

调用HtmlTestRuuner进行报告:

entrance.py

import test_123.Common.HTMLTestRunner
import unittest
import logging
from time import strftime, localtime, time
from test_123.TestSuites.testHome import TestHome



suite = unittest.TestSuite()
   # 获取TestSuite的实例对象

suite.addTest(TestHome('test_login'))
# 把测试用例添加到测试容器中

now = strftime("%Y-%m-%d-%H_%M_%S", localtime(time()))
# 获取当前时间

filename = now + "test.html"
# 文件名

fp = open(filename, "wb")
# 以二进制的方式打开文件并写入结果

runner = test_123.Common.HTMLTestRunner.HTMLTestRunner(
    stream=fp,
    verbosity=2,
    title="51.test",
    description="测试报告的详情")

runner.run(suite)
fp.close()

log_format = '%(asctime)s - %(levelname)s - %(message)s'
logging.basicConfig(filename="server.log", filemode='a+', format=log_format, level=logging.DEBUG)

6.当用例进行了测试后,对测试用例发送到自己邮箱,这个在搭建在Jenkins上时就可以定时看报告

#!/usr/bin/python3
import os
import time
import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from test_123.entrance import filename
import test_123.getcwd
from test_123.Common.config import Config
from test_123.Common.log import log1



config = Config()

#rq = time.strftime('%Y%m%d', time.localtime(time.time()))  # 获取本地时间 转换成日期
my_sender = config.config_read('sender', 'email')  # 发件人邮箱账号
my_pass = config.config_read('sender', 'password')  # 发件人邮箱密码
usernmae = config.config_read('sender', 'username')  # 发件人姓名 #
my_user = config.config_read('addressed','heemail')  # 收件人邮箱

path = test_123.getcwd.get_cwd()

file = 'E:\\untitled\\test_123\\Common\\'+ filename#附件路径


def mail():
    ret = True
    try:

        # 构造一个邮件体:正文 附件
        msg = MIMEMultipart()
        msg['Subject'] = "51测试"  # 主题
        msg['From'] = my_sender  # 发件人
        msg['To'] = my_user  # 收件人

        # 构建正文
        part_text = MIMEText("这个是UI测试,HTMLtextrunner测试报告")
        msg.attach(part_text)  # 把正文加到邮件体里面去

        # 构建邮件附件
        # file = file           #获取文件路径
        part_attach1 = MIMEApplication(open(file, 'rb').read())  # 打开附件
        part_attach1.add_header('Content-Disposition', 'attachment', filename=file)  # 为附件命名
        msg.attach(part_attach1)  # 添加附件


        server = smtplib.SMTP_SSL("smtp.qq.com", 465)  # 发件人邮箱中的SMTP服务器,设置端口是465
        server.login(my_sender, my_pass)  # 括号中对应的是发件人邮箱账号、邮箱密码
        server.sendmail(my_sender, [my_user, ], msg.as_string())  # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
        server.quit()  # 关闭连接
    except Exception:  # 如果 try 中的语句没有执行,则会执行下面的 ret=False
        ret = False
    return ret

ret = mail()
if ret:
    print("邮件发送成功")
else:
    print("邮件发送失败件")

到这里就简单介绍了一下过程,水平不足,可能说得不太明白

 

如果大家需要的话,可以找我要一下全部源码

相关标签: selenium