python数据驱动ui自动化框架_UI自动化测试及框架

UI自动化测试及框架

python + pytest框架

依赖包:pytest(单元测试框架)

allure-pytest(生成html报告)

pytest-html(生成html报告)

selenium(web自动化工具)

appium(app自动化工具)

parameterized(参数化)

目录结构:base(封装PO基类,对象库层基类、操作层基类)

page(封装PO页面对象类,定义对象库层、操作层、业务层)

script(存放测试的脚本)

data(存放测试数据)

report(存放测试报告)

log(日志目录)

screenshot(存放截图)

config.py(定义项目的配置信息)

conftest.py(专门存放fixture的配置文件,跨.py文件调用)

utils.py(自定义工具类)

pytest.ini(pytest配置文件)

PO模式先确定几个页面,根据对应的页面去创建页面对象的文件

确定每个页面要用到多少个元素对象库层

操作层

业务层

utils.py预览:

获取浏览器驱动:

# 定义工具类import timefrom selenium import webdriverfrom selenium.webdriver.common.by import Byclass UtilsDriver:    _mp_driver = None  # 表示的是自媒体平台的浏览器驱动    _mis_driver = None  # 表示的是后台管理的浏览器驱动    _app_driver = None  # 表示的是app的驱动    # 定义获取自媒体平台的浏览器驱动    @classmethod    def get_mp_driver(cls):        if cls._mp_driver is None:            cls._mp_driver = webdriver.Chrome()            cls._mp_driver.maximize_window()            cls._mp_driver.get("http://ttmp.research.itcast.cn/")        return cls._mp_driver

退出浏览器驱动:

# 定义退出自媒体平台的浏览器驱动    @classmethod    def quit_mp_driver(cls):        if cls._mp_driver is not None:            cls.get_mp_driver().quit()            cls._mp_driver = None

获取app驱动:

from appium import webdriver as app_driver    # 定义获取app的驱动    @classmethod    def get_app_driver(cls):        if cls._app_driver is None:            des_cap = {                "platformName": "android",  # 表示的是android  或者ios                "platformVersion": "5.1.1",  # 表示的是平台系统的版本号                "deviceName": "****",  # 表示的是设备的ID名称(如果只有一个设备可以用****来代替)                "appPackage": "com.itcast.toutiaoApp",  # 表示app的包名                "appActivity": ".MainActivity",  # 表示的是app的界面名                "noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作                "resetKeyboard": True,  # 重置设备的输入键盘                "unicodeKeyboard": True  # 采用unicode编码输入            }            cls._app_driver = app_driver.Remote("http://127.0.0.1:4723/wd/hub", des_cap)        return cls._app_driver

退出app驱动:

# 定义退出app驱动的方法    @classmethod    def quit_app_driver(cls):        if cls._app_driver is not None:            cls.get_app_driver().quit()            cls._app_driver = None

base.py类预览:

定义获取浏览器驱动和定义显示等待的基类:对象库层基类封装

# 定义自媒体平台的基类from selenium.webdriver.support.wait import WebDriverWaitfrom utils import UtilsDriver# 对象库层基类封装class BasePage:    def __init__(self):        self.driver = UtilsDriver.get_mp_driver()  # 获取自媒体浏览器驱动    def get_element(self, location):        wait = WebDriverWait(self.driver, 10, 1)        element = wait.until(lambda x: x.find_element(*location))        return element

定义输入文本操作的基类:操作层基类封装

# 操作层基类封装class BaseHandle:    def input_text(self, element, text):        element.clear()        element.send_keys(text)

xxx_page.py预览:

定义对象库层:

1、继承对象库层基类、重写__init__方法、定位元素

# 自媒体平台的发布文章页面对象from selenium.webdriver.common.by import Byfrom base.mp.base import BasePage, BaseHandle# 定义对象库层from utils import UtilsDriver, choice_channelclass PublishPage(BasePage):    def __init__(self):        super().__init__()        # 文章名称输入框        self.title = By.XPATH, "//*[@placeholder='文章名称']"        # iframe元素对象        self.iframe_ele = By.ID, "publishTinymce_ifr"        # 文章内容输入框        self.content = By.CSS_SELECTOR, ".mce-content-body "        # 封面选择        self.cover = By.XPATH, "//*[@role='radiogroup']/label[4]/span[2]"        # 频道选择        self.channel = By.XPATH, "//*[@placeholder='请选择']"        # 发表按钮        self.publish_btn = By.CSS_SELECTOR, "[class='el-button filter-item el-button--primary']"

2、返回元素:return ...

# 找文章的标题    def find_title(self):        return self.get_element(self.title)    # 找切换的iframe    def find_iframe(self):        return self.get_element(self.iframe_ele)    # 找文章内容输入框    def find_input_kw(self):        return self.get_element(self.content)    # 定位选择封面    def find_cover(self):        return self.get_element(self.cover)    # 定位频道选择框    def find_channel_choice(self):        return self.get_element(self.channel)    # 定位发表按钮    def find_publish_btn(self):        return self.get_element(self.publish_btn)

定义操作层:

继承操作层基类、实例化对象库层、操作点击、输入、切换iframe等

# 定义操作层class PublishHandle(BaseHandle):    def __init__(self):        self.publish_page = PublishPage()        self.driver = UtilsDriver.get_mp_driver()    # 输入文章标题    def input_title(self, title):        self.input_text(self.publish_page.find_title(), title)    # 输入文章内容    def input_content(self, content):        # 切换到iframe当中        self.driver.switch_to.frame(self.publish_page.find_iframe())        # 输入文章内容        self.input_text(self.publish_page.find_input_kw(), content)        # 切回到默认首页        self.driver.switch_to.default_content()    # 选择封面    def choice_cover(self):        self.publish_page.find_cover().click()    # 选择频道    def choice_channel(self, channel):        choice_channel(self.driver, self.publish_page.find_channel_choice(), channel)    # 点击发布按钮    def click_publish_btn(self):        self.publish_page.find_publish_btn().click()

定义业务层:

继承操作层,调用操作层的方法

# 定义业务层class PublishProxy:    def __init__(self):        self.publish_handle = PublishHandle()    # 发布文章    def publish_article(self, title, content, channel):        # 输入文章标题        self.publish_handle.input_title(title)        self.publish_handle.input_content(content)        self.publish_handle.choice_cover()        self.publish_handle.choice_channel(channel)        self.publish_handle.click_publish_btn()

script - Test测试类:

定义测试用例脚本:

实例化业务层 - setup_class,退出驱动 - teardown_class

# 定义测试类from page.mp.home_page import HomeProxyfrom page.mp.login_page import LoginProxyfrom page.mp.publish_page import PublishProxyfrom utils import UtilsDriver, is_existclass TestPublishArticle:    # 定义类级别的fixture初始化操作方法    def setup_class(self):        self.login_proxy = LoginProxy()        self.home_proxy = HomeProxy()        self.publish_proxy = PublishProxy()    # 定义类级别的fixture销毁操作方法    def teardown_class(self):        UtilsDriver.quit_mp_driver()

定义用例:调用业务层里面的方法,断言

# 定义登录的测试用例    def test_login(self):        self.login_proxy.login("13012345678", "246810")   # 登录        username = self.home_proxy.get_username_msg()  # 获取登录后的用户名信息        assert "test123" == username   # 根据获取到的用户名进行断言    # 定义测试方法    def test_publish_article(self):        self.home_proxy.go_publish_page()   # 跳转到发布文章页面        self.publish_proxy.publish_article("发布文章_0710_14", "发布文章_0710_14发布文章_0710_14", "数据库")        assert is_exist(UtilsDriver.get_mp_driver(), "新增文章成功")

pytest配置文件

pytest的配置文件有固定的三个名称:(三选一即可)pytest.ini

tox.ini

setup.cfg

这三个配置文件是放在项目的根目录下

配置内容如下:

[pytest]  # 标识当前配置文件是pytest的配置文件addopts = -s -v # 标识pytest执行时增加的参数testpaths = ./scripts # 匹配搜索的目录python_files = test_*.py # 匹配测试文件python_classes = Test* # 匹配测试类python_functions = test_* # 匹配测试方法

配置文件弄好了就可以在 命令行输入pytest就可以执行

pytest测试报告

安装

pip install pytest-html

pytest配置文件addopts加上--html=report/report.html

addopts = -s -v --html=report/report.html

allure-pytest测试报告

安装

pip install allure-pytest

添加测试步骤使用的方法:

@allure.step(title="步骤名称")title名称必须要带上。

# 定义操作层class LoginHandle(BaseHandle):  def __init__(self):    self.login_page = LoginPage()  # 输入手机号码  @allure.step(title="输入手机号码")  def input_mobile(self, mobile):  self.input_text(self.login_page.find_mobile(),mobile)  # 输入验证码  @allure.step(title="输入验证码")  def input_code(self, code):    self.input_text(self.login_page.find_code(),code)

生成allure测试报告数据

要在pytest.ini配置文件的addopts项中,增加一项:

addopts = -s -v --alluredir reportreport表示的是生成报告数据存放的目录

将allure测试报告数据生成HTML测试报告

allure转换工具安装解压allure-2.7.0工具包

将解压的目录放到不经常移动的路径下面

找到解压目录的bin目录,并将bin目录的路径添加到环境变量当中

在命令行当中输入 allure,如果有以下提示信息,就说明是成功的2670e72c3c21e529644a0fe9e16ff64554f27e35.png

使用的命令:

allure generate report -o report/html --cleanallure generate 表示的是生成测试报告report 表示的是测试报告的数据目录-o report/html 表示输出html测试报告的目录为 report/html--clean 表示的是清除之前 report/html里面的报告文件

拓展:参数化

形式:

case_data = get_case_data(BaseDir + "/data/mp/test_login_data.json")# 定义登录的测试用例    @pytest.mark.parametrize("username, code, expect", case_data)    @allure.severity(allure.severity_level.CRITICAL)    def test_login(self, username, code, expect):

实际用法:

# 定义测试类import loggingimport allureimport pytestfrom config import BaseDirfrom page.mp.home_page import HomeProxyfrom page.mp.login_page import LoginProxyfrom page.mp.publish_page import PublishProxyfrom utils import UtilsDriver, is_exist, get_case_datacase_data = get_case_data(BaseDir + "/data/mp/test_login_data.json")@pytest.mark.run(order=1)class TestPublishArticle:    # 定义类级别的fixture初始化操作方法    def setup_class(self):        self.login_proxy = LoginProxy()        self.home_proxy = HomeProxy()        self.publish_proxy = PublishProxy()    # 定义类级别的fixture销毁操作方法    def teardown_class(self):        UtilsDriver.quit_mp_driver()    # 定义登录的测试用例    @pytest.mark.parametrize("username, code, expect", case_data)    @allure.severity(allure.severity_level.CRITICAL)    def test_login(self, username, code, expect):        logging.info("用例的数据如下:用户名:{}, 验证码:{}, 预期结果:{}".format(username,                                                              code, expect))        print(username, code)        self.login_proxy.login(username, code)   # 登录        allure.attach(UtilsDriver.get_mp_driver().get_screenshot_as_png(), "登录截图", allure.attachment_type.PNG)        username = self.home_proxy.get_username_msg()  # 获取登录后的用户名信息        assert expect == username   # 根据获取到的用户名进行断言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值