selenium UI自动化PO模式测试框架搭建

这篇具有很好参考价值的文章主要介绍了selenium UI自动化PO模式测试框架搭建。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、UI自动化规划

熟悉业务-》确定方案-》选取场景-》了解前端-》定位元素-》编写脚本-》运行优化-》回归报告-》项目汇总
价值意义:
自动化执行需要:模块化
需要可制定化执行
可复用性
PO模式:
将页面定位和业务分开,元素的定位单独处理,执行脚本单独封装。维护方便。
封装BasePage类,在基类中具有webdriver的实例的属性,把每个页面继承BasePage,通过driver管理每个页面的元素,将页面再细分一个个方法。Testcase依赖page类,进行组织化的测试步骤。
维护:
元素变化了:维护每个page
测试步骤变化:维护Testcase
每个page的常规操作封装基类:
点击动作、输入、文本处理、滑动、弹窗……
业务分类:
登录模块(登录、注册新用户)、
首页模块(菜单栏、主页显示)、
管理模块(数据列表展示、新增、分类、……)、
用户模糊(用户数据信息展示)……
功能测试用例依据以此分类设计

2、PageObject设计模式

系统梳理分类

代码层面分类:
系统System:
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
其中:
pageObjects
testCase
common
configs
utils
outFiles文件夹(logs/reports/screenshoot
docs文件夹
data文件夹
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
PO模式从下往上,从底层开始写:driver-》BasePage-》pages-》test执行-》报告
python+selenium+pytest+allure .

3、PO模式封装

1、驱动模块(固定写法)

封装驱动写在:common包下
新建myDriver.py文件,建一个兼容浏览器的驱动类,就是dirver

"""
驱动模块
    1、考虑到浏览器的兼容性,可以分为主流的几个浏览器驱动
        1、谷歌
        2、火狐
        3、其他
"""

from selenium import webdriver
from configs.config import implicitly_wait_time

# 设置单例模式
'''
类创建实例:
    1、先调用—__new__()创建方法,一般类中不写,自动调用
    2、再调用初始化方法__init__()
  判断一个类是否有实例,如果有,就不会创建新的实例  
'''

# 哪一个类的实例需要使用单例模式,就直接继承这个类(`固定写法`)
class Single(object):
	#new方法创建对象
	def __new__(cls, *args, **kwargs):
	# 判断当前的类是否已经实例化
		if not hassttr(cls, '_instance'):
			cls._instance = super().__new__(cls)# super是父类的new方法
		return cls._instance
	

class Driver(Single):
    # 新建一个初始值
    _driver = None

    # 判断使用浏览器,---------默认指定谷歌浏览器
    def get_driver(self, browser_name='chrome'):
        if self._driver is None:
            if browser_name == "chrome":
                self._driver = webdriver.Chrome()
            elif browser_name == "firefox":
                self._driver = webdriver.Firefox()
            else:
                raise (f"没有这个{browser_name}浏览器,请使用可用浏览器打开")
            # 设置隐式等等时间---设置`**全局变量`**等等时间5s
            self._driver.implicitly_wait(implicitly_wait_time)
            # 浏览器对大化
            self._driver.maximize_window()
        return self._driver  # 返回浏览器对象


if __name__ == '__main__':
    Driver().get_driver('chrome')# 创建实例对象,调用对应的方法,传什么浏览器使用什么浏览器

驱动模块封装完毕,后续只需要调用Driver().get_driver('chrome')就可以使用webdriver进行元素定位
等同于对driver= webdriver.Chrome()的封装,方便兼容不同浏览器。

1、隐式等待时间全局变量参数化
configs包下创建config文件,设置隐式等待时间参数5s或者10s,自定义

implicitly_wait_time = 5

2、基类封装(基本框架固定写法)

基类写在:common包下,新建一个文件basePage.py

  • 创建基类basePage
    作用:1、把基本的页面操作封装好,给其他页面继承使用
    包含:2、点击操作(click)、输入框输入(input_text)、获取元素属性值(get_attrbute)、元素可见(visibility)、截图(save_screenshot)、清除(clear),获取文本内容(get_text)、显示等待presence_of(元素可见(visibility_of),可操作点击(clickable))……等操作指令的封装
from common.myDriver import Driver
import time
import os.path
from utils.handle_logs import logger
from utils.handle_path import screenshot_path, config_path
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from utils.handle_yaml import get_yaml_data
from common.myDriver import Driver
from configs_delivery.config import wait_timeout, wait_poll_frequency

class BasePage:
    def __init__(self):  # 调用basepage 需要的浏览器对象,默认谷歌浏览器
        self._driver = Driver().get_driver()

    # ------------------------封装截图方法---------------------------
    # 截图操作:可以使用浏览器对象去调用,也可以使用元素调用
    def get_page_screenshot(self, action=None):
        # 注意截图的描述:哪个动作+时间
        curTime = time.strftime('%Y%m%d%H%M%S', time.localtime())
        filepath = os.path.join(screenshot_path, f'{action}_{curTime}.png')
        # 截图操作
        self._driver.save_screenshot(filepath)

    # ----------------------封装页面操作------------------------
    # 1、封装-输入-操作
    def input_text(self, locator, text, action=None):
        '''

        :param locator: 元素定位: locator定义为包含-元素定位方法-和-定位方式-的包 ----['id','name']
        :param text: 输入文本的内容
        :param action: 执行的动作描述,缺省参数
        
        '''
        # 1、元素定位
        # find_element(定位方式,定位表达式)
        element = self._driver.find_element(*locator)  # "*"号解包
        # 2、很多输入框有默认提示文本,需要先清除
        element.clear()
        # 3、输入值
        element.send_keys(text)
    # 2、封装-点击-操作
    def click(self, locator, action=None):
        # 1、元素定位
        # find_element(定位方式,定位表达式)
        element = self._driver.find_element(*locator)  # "*"号解包
        # 2、点击
        element.click()
    # 3、封装-清空-操作
    def clear(self, locator, action=None):
        # 1/元素定位
        element = self._driver.find_element(*locator)
        # 2/清空
        element.clear()    
	# 4、封装 -获取文本内容-操作
    def get_text(self, locator, action=None):
        return WebDriverWait(
            self._driver,
            timeout=wait_timeout,
            poll_frequency=wait_poll_frequency).until(
            EC.visibility_of_element_located(locator)).text 
  
   # ----封装显式等待---判断元素是否存在,如果没有获取到元素,使用显示等待判断----日志及截图-------
    def element_is_presence(
            self,
            locator,
            action=None,
            timeout=5,
            poll_frequency=0.5):
        '''

        :param locator: 定位元素和定位方法和表达式,包('','')
        :param action: 动作描述,
        :param timeout: 等待时间设置
        :param poll_frequency: 等待频率
        '''
        # 1/设置显式等待时间
        try:
            WebDriverWait(
                self._driver,
                timeout=timeout,
                poll_frequency=poll_frequency).until(
                EC.presence_of_element_located(locator))
        except BaseException:
            # 1/打印log信息
            log.error(action)
            # 2/截图
            self.get_page_screenshot(action)
            # 3/元素不存在返回False
            return False
        # 如果存在返回True
        return True

---------------------------------------------------

  • 1、路径配置
    上述:screenshot_path,在公共方法utils中封装,新建handle_path.py
    ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
    需要的路径都可以提前封装好:(固定写法
import os

# 1、工程路径
# os.path.obspath(__file__)  当前文件路径
# os.path.dirname()------获取上一层路径
project_path = os.path.dirname(os.path.dirname(__file__))
# 2、截图路径
screenshot_path = os.path.join(project_path, r'outFiles\screenshot')
# 3、日志路径
logs_path = os.path.join(project_path, r'outFiles\logs')
# 4、测试数据路径
testcase_path = os.path.join(project_path, 'data')
# 5、测试报告路径
reports_path = os.path.join(project_path, r'outFiles\reports\tmp')
# 6、配置路径
config_path = os.path.join(project_path, 'configs')

if __name__ == '__main__':
    # print(project_path)
    # print(screenshot_path)
    # print(logs_path)
    # print(reports_path)
    # print(testcase_path)
    print(config_path)
  • 2、log的封装(固定方法)
    utils包下新建handle_logs.py
    基类中封装显示等待的时间需要截图、并抓取log
"""
日志相关内容
    1、日志的输出渠道:文件xxx.logs        控制台输出
    2、日志级别:CRITICAL-ERROR-WARNING-INFO-DEBUG
    3、日志内容:2023-03-30 18:42:12, 234 INFO XXXXXXXX
        年月日.时分秒.级别-哪行代码出错-具体内容
"""
import logging
import datetime
from utils.handle_path import logs_path


def logger(file_Log=True, name=__name__):
    logDir = f'{logs_path}-{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}.txt'
    # 1/创建日志收集器对象
    logObject = logging.getLogger()
    # 2/ 设置日志的级别
    logObject.setLevel(logging.DEBUG)
    # 3/ 日志内容格式
    fmt = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'
    formater = logging.Formatter(fmt)

    if file_Log:  # log文件模式
        # 设置日志渠道 -文件输出
        handle = logging.FileHandler(logDir, encoding='utf-8')
        # 日志内容与渠道绑定
        handle.setFormatter(formater)
        # 把日志对象与渠道绑定
        logObject.addHandler(handle)
    else:
        # 设置日志渠道控制台 控制台输出
        handle2 = logging.StreamHandler()
        # 日志内容与渠道绑定
        handle2.setFormatter(formater)
        # 把日志对象与渠道绑定
        logObject.addHandler(handle2)
    return logObject


log = logger()  # 控台输出日志

if __name__ == '__main__':
    log = logger()  # 控制台输出日志
    log.debug('日志信息:')
  • 3、
    locator的定义:
    selenium4 升级后定位方式变化为:driver.find_element(By.定位方法, '定位方式')格式
    例如:ID定位某个元素:

    login = driver.find_element(By.ID, 'btnLogin')
    

    locator即是By.定位方法, '定位方式'这个包

  • 4、封装页面操作:后续需要自行添加函数封装即可

    • 显示等待如上封装,可见元素定位的封装方法如下
 def element_is_presence(
            self,
            locator,
            action=None,
            timeout=5,
            poll_frequency=0.5):
        '''
   def element_is_visibility(
            self,
            locator,
            action=None,
            timeout=5,
            poll_frequency=0.5):
        # 1/设置显式等待可见元素定位时间
        try:
            ele = WebDriverWait(
                self._driver,
                timeout=timeout,
                poll_frequency=poll_frequency).until(
                #判断元素是否可见再执行定位
                EC.visibility_of_element_located(locator))
        except BaseException:
            # 1/打印log信息
            log.error(action)
            # 2/截图
            self.get_page_screenshot(f'{action}-元素定位不到')
            # 3/元素不存在直接抛出异常信息
            raise
        # 如果存在返回元素本身
        return ele 

而封装的页面操作使用可见元素定位的方法修改为:

 # 2、输入操作
    def click(self, locator, action=None):
        # 1、元素定位
        # element_is_visibility(定位方式,定位表达式)。元素是可见的再进行定位
        element = self.element_is_visibility(locator)
        # 2、点击
        element.click()
  • 封装定位元素是可点击的方法
    # ----------------------可见元素且是可点击的-----------------
    def element_is_clickable(
            self,
            locator,
            action=None,
            timeout=5,
            poll_frequency=0.5):
        # 1/设置显式等待可见元素定位时间
        try:
            ele = WebDriverWait(
                self._driver,
                timeout=timeout,
                poll_frequency=poll_frequency).until(
                # 判断元素是否可点击执行定位
                EC.element_to_be_clickable(locator))
        except BaseException:
            # 1/打印log信息
            log.error(action)
            # 2/截图
            self.get_page_screenshot(f'{action}-元素定位不到')
            # 3/元素不可点击直接抛出异常信息
            raise
        # 如果存在返回元素本身
        return ele

相应页面的操作封装方法:

 # 2、输入操作
    def click(self, locator, action=None):
        # 1、元素定位
        # element_is_visibility(定位方式,定位表达式)。元素是可见的再进行定位
        element = self.element_is_clickable(locator)
        # 2、点击
        element.click()
  • 5、wait_timeout, wait_poll_frequency在config中提前配置号
    ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
    ---------------------------------.----------------------------------------

3、设置yaml定位元素(固定写法)

config包下新建一个文件locator.yaml 写定位配置数据

  • 【”定位方法“,”定位方式“】的写法即:.find_element_by_id('username '),取id和对应的属性值,八大元素定位法之一。
  • 若采用css或者xpath写法:message_text: [‘css selector’,‘.el-message--error’] #登录错误消息文本:css selector即定位方法,.el-message--error定位方式。构成了字典格式{xxx:{ss:['v','v'],ss:['v','v'],ss:['v','v']},{[],[]},{[],[]}},后续通过字典的键获取值执行操作
LoginPage:
  username_input: ['id','username']#登录账户
  pwd_input: ['id','pwd']#登录密码
  login_btn: ['id','btnLogin']#登录按钮
  message_text: ['css selector','.el-message--error'] #登录错误消息文本
OtherPage:
  home_button: ['xpath','//*[text()="首页"]'] #首页按钮
  logout_button: ['xpath',"//span[text()='退出']"] #退出按钮
  personal_button: ['xpath','//img']  #个人中心按钮
  

4、读取yaml定位数据(固定写法)

utils包下新建一个文件,handle_yanl.py 处理获取yaml数据

import yaml
from  utils.handle_path import config_path

def get_yaml_data(fileDir):
    #方法一
    # # 1、打开文件
    # fo = open(fileDir, 'r', encoding='utf-8')
    # # 2、读取文件
    # yaml_data = yaml.load(fo, Loader=yaml.FullLoader)
    # return yamldata
    #方法二
    with open(fileDir, encoding='utf-8') as fo:
        return yaml.safe_load(fo.read())


if __name__ == '__main__':
    print(get_yaml_data(f'{config_path}\locator.yaml'))

5、写PO页面-继承基类

先写个基础常规的页面:后续还有优化的方法

在pageObject新建操作模块页面:比如:login_page.py,继承basePage
登录页面:

from  utils.handle_path import config_path
from common.basePage import BasePage
from configs.config import url
from time import sleep
from utils.handle_yaml import get_yaml_data


class LoginPage(BasePage): # 继承基类
    def to_login_page(self):
        self._driver.get(url)  # 打开登录页面,url在config包中配置
        return self		#登录网址返回self本身,方便后续调用

    # 1、登录
    def login(self, username, pwd):
    	#读取yaml定位参数locator['LoginPage']提取键值数据
        locator = get_yaml_data(f'{config_path}\locator.yaml')['LoginPage']
        # 输入账号,locator['username_input']获取定位方法和定位方式,xxx填写容
        self.input_text(locator['username_input'], 'username', action='输入账号')
        # 输入密码
        self.input_text(locator['pwd_input'], 'pwd', action="输入密码")
        # 点击登录按钮
        self.click(locator['login_btn'], action="点击登录按钮")
        sleep(5)


if __name__ == '__main__':
    # 登录页面
    LoginPage().to_login_page().login('uername','pwd' )

------------------------**注**---------------------------------

  • 1、urlconfigs中配置后再调用
    ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
    定位获取优化方法:

locator = get_yaml_data(f’{config_path}\locator.yaml’)[‘LoginPage’]
self.input_text(locator[‘username_input’], ‘username’, action=‘输入账号’)
一个项目上百个定位元素,每次都通过get_yaml_data文件处理数据,然后再通locator
一个获取定位方法和定位方式比较繁琐。
so:设计了巧妙的定位调用方法,脚本中对于定位不可见,但是却省事省力的方法:

在设计locator.yaml文件是,把字典的键设计成语po页面的类同名即可。
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
在基类中封装一下:

import time
import os.path
from utils.handle_logs import logger
from utils.handle_path import screenshot_path, config_path
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from utils.handle_yaml import get_yaml_data
from common.myDriver import Driver

class BasePage:
    def __init__(self):  # 调用basepage 需要的浏览器对象,默认谷歌浏览器
        self._driver = Driver().get_driver()
        # --------------获取所有需要的定位的元素参数,且实现对号入座
        # loginpage-----只获取loginPage
        # [self.__class__.__name__]获取到对应的类的名字,yaml定位元素时命名与后续页面操作类的名字保持一样
        locator = get_yaml_data(
            config_path + r'\locator.yaml')[self.__class__.__name__]  # 字典
        # print(locator)
        for k, v in locator.items():  # k自定义键名,v(定位方法,定位表达式)
            setattr(self, k, v)
            """
            setattr(self, k, v)
                1、self是页面的实例
                2、使用set attrbute--setattr
                3、创建self这个实例的新的属性,将v赋值给她,self.k = v
                例子:
                class Test:
                    pass
                test = Test()  创建实例
                #对实例再创建属性,并将对应属性的值赋给它
                setattr(test, 'name', '123')
                print(test.name)
                结果就是test.name = 123
            """

------------------------**注**-----------------------------
上述locator的封装方式就是通过[self.__class__.__name__]获取到对应po页面的本身类的名字

 locator = get_yaml_data(
            config_path + r'\locator.yaml')[self.__class__.__name__]  # 字典格式

例如登录的定位元素打印出来是:
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
所以对字典处理:setattr方法将键值和self绑定

for k, v in locator.items():  # k自定义键名,v(定位方法,定位表达式)
            setattr(self, k, v)

则,self.k = v,则最终可以获取[‘id’, ‘username’],也就是我们需要的,定位方法和定位方式
基类封装中可以直接使用self.自定义键名

find_element(定位方式,定位表达式) ==find_element(self.自定义键名)

则优化后登录页面可以写成:

from pageObjcets.homePage import HomePage
from common.basePage import BasePage
from configs.config import url
from time import sleep


# 登录类,继承基类
class LoginPage(BasePage):
    def to_loginPage(self):
        self._driver.get(url)  # 打开登录页面
        return self

    # 1、登录
    def login(self, username, pwd):
        # 输入账号self.username_input:优化后的方法
        self.input_text(self.username_input, username, action='输入账号')
        # 输入密码
        self.input_text(self.pwd_input, pwd, action="输入密码")
        # 点击登录按钮"self.login_btn"就是优化后的使用方法
        self.click(self.login_btn, action="点击登录按钮")
        sleep(2)


if __name__ == '__main__':
    # # 登录页面
    homepage = LoginPage().to_loginPage().login('xxx', 'xxx')
    # 首页展示
    # # print('这个类的名字是', LoginPage().__class__.__name__)

这样的话,整个测试框架中看不到定位:只需要配置locator.yaml即可。后续保持键与各个page的类名一样即可。
-------------------------------.----------------------------------

6、测试用例yaml

data文件夹下新建一个文件loginData.yaml
登录的的测试用例编写格式:

# 登录成功用例
- ['usernamexxx','pswxxx'] # 账号密码正确
---   #分隔符
# 登录失败用例
- [['xpath',"//*[contains(text(),'该用户不存在!')]"],'该用户不存在!','usernamexx','pswxxx']
- [['xpath',"//*[contains(text(),'输入的密码错误!')]"],'输入的密码错误!','usernamexx','pswxxx']
- [['xpath',"//*[contains(text(),'该用户不存在!')]"],'该用户不存在!','','111111']
- [['css selector','.el-form-item__error'],'The password can not be less than 5 digits','xxxx','']
- [['css selector','.el-form-item__error'],'The password can not be less than 5 digits','','']

用例编写完,需要进一步处理数据成为自己想要的:[(‘username’,‘pwd’),(‘us’,‘pwd’),(‘usme’,‘wd’)]这种格式的,就可以使用pytest.mark.parametrize()参数化了。
在utile包新建一个handle_yaml.py文件,因为之前处理定位yaml有了,就在当前文件下封装个读取用例的get_case_yaml函数:因为我们把正向用例和反向用例写在一个yaml文件里,分隔成两个yaml文件数据了,需要单独处理

def get_case_yaml(filedir):
    caselist = []
    # 1、打开文件
    fo = open(filedir, 'r', encoding='utf-8')
    # 2、读取文件
    testcases = yaml.load(fo, Loader=yaml.FullLoader)
    for one in testcases:
        caselist.append(one)
    return caselist
    # print(testcases)

test_login.py提取数据时需要使用角标提取就行了:
get_case_yaml(filedir[0]),提取的就是正确的密码和账号
get_case_yaml(filedir[1]),提取反向用例的数据

7、pytest测试模块+allure测试报告输出

testCase包下新建一个文件test_login.py
1、参数化测试用例:@pytest.mark.parametrize('username, pwd', get_yamlData(testcase_path+r'\loginData.yaml'))
2、优化测试报告:
标题level: ---------------------测试步骤:
@allure.epic() -----------------with allure.step(’ ‘):
@allure.feature()--------------
@allure.story()
@allure.title()
测试报告输出:标红的部分
pytest.main([‘test_login.py’, '--alluredir', reports_path, '--clean-alluredir'])
os.system(f'allure serve {reports_path}')
3、测试报告版本展示:
在reports/tmp下新建一个文件:environment.properties文件,也就是在你生成报告的路径下新建这个文件
里面填写你测试软件平台的版本信息,丰富allure测试报告的展示

Browser=Chromium
Browser.Version=21.1.18
Stand=test
python.Version=3.9.2
allure.version=2.13.3

pytest测试代码如下:

import os, pytest, allure
from utils.handle_yaml import get_yamlData
from pageObjcets.loginPage import LoginPage
from utils.handle_path import testcase_path, reports_path
loginData = f"{testcase_path}/login_cases.yaml"

@allure.epic('登录模块test')
@allure.story('登录模块test')
class TestLogin:  # 测试类
    @pytest.mark.parametrize('username, pwd',
                             get_case_yaml(loginData)[0])
    @allure.title('登录成功case')
    def test_login(self, username, pwd):
    	#第一步:输入账户密码登录
        with allure.step('输入账户密码执行登录'):
            # 1/登录
            homepage = LoginPage().to_loginPage().login(username, pwd)
            # 2/登录是否成功,断言四否具有首页元素。assert断言失败后就无法继续执行。
            # assert homepage.element_is_presence(homepage.home_button)
            # 2/解决方案:assume断言失败后可以继续执行下一步,有时间也需要反向的用例测试失败可以继续下一步执行
        # 第2步:验证登录成功
        with allure.step('验证登录是否成功'):
            pytest.assume(
                homepage.element_is_presence(
                    homepage.home_button,
                    action='登录后验证首页'))
        # 第3步:退出返回到登录页面,方便后续的反向用例执行
        with allure.step('退出返回到登录页面'):
            # 3/做完登录退回到登录页面
            homepage.to_login_page(action='退出登录')


if __name__ == '__main__':
    pytest.main(['-sq', 'test_login.py', '--alluredir', reports_path, '--clean-alluredir'])
    os.system(f'allure serve  {reports_path}')

验证首页元素,需要先在projectPage页新建一个homePage.py文件,因为首页不属于登录页,需要写在首页中:

 # 点击回到首页
def homepage(self):
    self.click(self.home_button, '点击首页')    

homepage.element_is_presence(homepage.home_button,action='登录后验证首页'))中的home_button即是首页元素。

反向用例处理:
测试反向用例若使用assert,断言失败就无法继续执行:
引入新的插件:assume
需要安装pytest-assume库,在pycharm终端使用命令安装:

pip3 install pytest-assume

ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
引自:https://blog.csdn.net/weixin_50829653/article/details/113179401
反向用例准备好了,在test_login.py再封装一个函数处理反向测试场景:
1、在locator.yaml准备好相应的登录失败的提示文本的元素定位:
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
2、编写处理反向用例代码

    # 执行反向用例,登录失败的场景
    @pytest.mark.parametrize('locator, expected, username, password',
                             get_case_yaml(loginData)[1])
    # @pytest.mark.skip(reason='先不跑')
    @allure.title('登录失败用例')
    def test_loginerr(self, locator, expected, username, password):
        with allure.step('执行登录'):
            homepage = LoginPage().login_page()
            homepage.login(username, password)

        with allure.step('断言登录失败提示'):
            pytest.assume(homepage.get_text(locator) == expected)
            # homepage.get_screenshot('报错截图')

四个参数分别对应用例中的定位元素(locator),期望结果(expected),账号和密码
通过BasePage的get_text方法获取登录失败提示文本信息,与期望对比,这里使用assert也行,建议使用assume,不然失败了就停止测试了。
通过装饰器mark.skip()选择是否跑反向用例

最后合起来的pytest执行脚本:

import os, pytest, allure
from utils.handle_yaml import get_yamlData
from pageObjcets.loginPage import LoginPage
from utils.handle_path import testcase_path, reports_path
loginData = f"{testcase_path}/login_cases.yaml"

@allure.epic('登录模块test')
@allure.story('登录模块test')
class TestLogin:  # 测试类
    @pytest.mark.parametrize('username, pwd',
                             get_case_yaml(loginData)[0])
    @allure.title('登录成功case')
    def test_login(self, username, pwd):
    	#第一步:输入账户密码登录
        with allure.step(' 1、输入账户密码执行登录'):
            # 1/登录
            homepage = LoginPage().to_loginPage().login(username, pwd)
            # 2/登录是否成功,断言四否具有首页元素。assert断言失败后就无法继续执行。
            # assert homepage.element_is_presence(homepage.home_button)
            # 2/解决方案:assume断言失败后可以继续执行下一步,有时间也需要反向的用例测试失败可以继续下一步执行
        # 第2步:验证登录成功
        with allure.step('2 、验证登录是否成功'):
            pytest.assume(
                homepage.element_is_presence(
                    homepage.home_button,
                    action='登录后验证首页'))
        # 第3步:退出返回到登录页面,方便后续的反向用例执行
        with allure.step(' 3、退出返回到登录页面'):
            # 3/做完登录退回到登录页面
            homepage.to_login_page(action='退出登录')

    # 执行反向用例,登录失败的场景
    @pytest.mark.parametrize('locator, expected, username, password',
                             get_case_yaml(loginData)[1])
    # @pytest.mark.skip(reason='先不跑')
    @allure.title('登录失败用例')
    def test_loginerr(self, locator, expected, username, password):
        with allure.step('1、执行登录'):
            homepage = LoginPage().login_page()
            homepage.login(username, password)
        with allure.step('2、断言登录失败提示'):
            pytest.assume(homepage.get_text(locator) == expected)
            # homepage.get_screenshot('报错截图')


if __name__ == '__main__':
    pytest.main(['-sq', 'test_login.py', '--alluredir', reports_path, '--clean-alluredir'])
    os.system(f'allure serve  {reports_path}')

8、PO模式结合fixture的数据清除与格式化

testCase包下新建一个conftest.py注:命名必须为conftest.py, pytest的规则命名。只有conftest才能识别


"""
scope指的是fixture的作用域:
      4种:
          function(函数)<class(类)<module(模块级别)<session(包)
auto
    1、手动调用执行
    2、自动执行
"""
import pytest
from time import sleep
from common.myDriver import Driver

@pytest.fixture(scope='session', autouse=True)
def start_running():
    print("------开始运行UI自动化测试-----")
    yield
    # 自动化完成之后,关闭浏览器进程
    sleep(3)    #避免浏览器关闭太快,最后一部操作了但响应时间时浏览器关闭太快导致问题。
    Driver().get_driver().quit()
    print("-----结束-UI自动化测试-----")

--------------------**注**--------------------------
1、sleep(3)是为了保证关闭退出浏览器过快而报错。有时候最后一步执行操作未完成就关闭了浏览器。
2、关于数据清除:例如在增加设置或者新增数据时,保证不改变别人的数据,我们只删除自己的数据,一般处理代码放在执行完成测试后:以下非登录模块的数据清除代码。删除代码编写在page模块中调用。

 # 1、测试完毕删除测试数据
    homepage.to_product_list().delete_first_product()
    # 2、回到首页方便后续执行测试
    homepage.to_home_page()

放置位置如下:
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
本地一键执行所有测试模块
run.bat的创建:
本地项目的路径下创建一个run.bat文件
ui自动化框架封装,seleniumUI自动化,web UI自动化测试,selenium,自动化,测试工具
在文件内使用如下:
cd到测试路径->pytest执行所有文件,->输出allure报告

cd ./testCase_polly
pytest -sv --alluredir ./outFiles/reports/tmp --clean-alluredir
allure serve ./outFiles/reports/tmp

操作汇总

1:需要主要的是操作导致刷新页面需要重新获取定位元素,否则会失效
2:若操作会导致切换页面,需要加一定强制等待sleep(3),不然很容易导致定位报错或者定位不到
3:conftest 的fixture配置退出浏览器或者结束关闭浏览器需要强制等待sleep(5),不然最后一步的执行可能会报错文章来源地址https://www.toymoban.com/news/detail-757975.html

到了这里,关于selenium UI自动化PO模式测试框架搭建的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • UI 自动化测试框架:PO 模式+数据驱动 【详解版】

    什么是 PO 模式? PO(PageObject)设计模式将某个页面的所有元素对象定位和对元素对象的操作封装成一个 Page 类,并以页面为单位来写测试用例,实现页面对象和测试用例的分离。 PO 模式的设计思想与面向对象相似,能让测试代码变得可读性更好,可维护性高,复用性高。

    2024年02月04日
    浏览(42)
  • Selenium Web自动化测试——基于unittest框架的PO设计模式

     🔥 交流讨论: 欢迎加入我们一起学习! 🔥 资源分享 : 耗时200+小时精选的「软件测试」资料包 🔥  教程推荐: 火遍全网的《软件测试》教程   📢 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 前面一直在讲接口自动化测试框架与案例分享,很少讲Selenium这个We

    2024年03月21日
    浏览(55)
  • Selenium自动化测试设计模式-PO模式

    在python自动化过程中,Selenium自动化测试中有一个名字常常被提及PageObject(思想与面向对象的特性相同),通过PO模式可以大大提高测试用例的维护效率。 不了解po设计模式的可自行百度 面向对象的特性 :封装、继承、多态 传统测试脚本的弊端: 测试脚本分离,维护成本高

    2023年04月08日
    浏览(49)
  • Selenium基于Python web自动化测试框架 -- PO

     🔥 交流讨论: 欢迎加入我们一起学习! 🔥 资源分享 : 耗时200+小时精选的「软件测试」资料包 🔥  教程推荐: 火遍全网的《软件测试》教程   📢 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 关于selenium测试框架首先想到的就是PO模型,简单说下PO模型 PO模型的

    2024年02月22日
    浏览(52)
  • 如何搭建自动化测试框架?资深测试整理的PO模式,一套打通自动化...

    Po模型介绍 1、简介 在自动化中,Selenium自动化测试中有一个名字经常被提及PageObject(思想与面向对象的特征相同),通常PO模型可以大大提高测试用例的维护效率 2、为什么要用PO 基于selenium2开始ui自动化测试脚本的编写不是多么艰巨的任务。只需要定位到元素,执行对应元素的

    2024年02月13日
    浏览(50)
  • PO设计模式是selenium自动化测试中最佳的设计模式之一

    Page Object Model:PO设计模式是selenium自动化测试中最佳的设计模式之一,主要体现在对界面交互细节的封装,也就是在实际测试中只关注业务流程就OK了传统的设计中,在新增测试用例之后,代码会有以下几个问题:1.易读性差:一连串的find element会使代码显得杂乱无章2.可扩展

    2024年02月11日
    浏览(40)
  • 微信小程序自动化测试框架 Minium——PO模式测试用例

    本文主要介绍PO模式的测试用例,PO模式优点及层级间的关系,相关配置及运行 minitest的测试小程序和测试case:minitest-demo miniprogram-demo :测试小程序 testcase :测试case,同时也包含文档的测试case testcase-PO :Page Object(PO) 模式的测试case PO模式是自动化测试项目开发实践的最佳设

    2024年02月07日
    浏览(55)
  • 让自动化测试秒杀繁琐操作?试试PO模式设计框架

    目录:导读 引言 po模式 优势:  目录解释: 页面对象设计模式: base基础层: page对象层:  test:测试层 data数据层:  common层:  untils:  config层: run层: report: 结语 你是否曾经因为每次更新功能都要重新写一堆自动化测试代码而感到疲惫不堪? 或者因为页面元素的频繁变

    2024年02月02日
    浏览(45)
  • 多测师肖sir___ui自动化测试po框架(升级)

    ui自动化测试po框架(升级) po框架 一、ui自动化po框架介绍 (1)PO是Page Object的缩写(pom模型) (2)业务流程与页面元素操作分离的模式,可以简单理解为每个页面下面都有一个配置class, 配置class就用来维护页面元素或操作方法 (3)提高测试用例的可维护性、可读取性

    2024年01月19日
    浏览(39)
  • 多测师肖sir___ui自动化测试po框架讲解版

    po框架 一、ui自动化po框架介绍 (1)PO是Page Object的缩写(pom模型) (2)业务流程与页面元素操作分离的模式,可以简单理解为每个页面下面都有一个配置class, 配置class就用来维护页面元素或操作方法 (3)提高测试用例的可维护性、可读取性 对比:传统的设计测试用例存

    2024年02月02日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包