python+appium自动化测试Page Object模式——微博登录代码封装

该网站上更新文章有延迟,如需查看关于python+appium文章,请前往testhome关注我哦。https://testerhome.com/topics/27802

一、什么是Page Object模式

Page Object 模式是selenium/appium自动化测试项目开发最佳测试设计模式,它将每个页面设计成一个类class,类中包含了页面中需要使用的元素(按钮、输入框、标题等),测试用例可以通过调用类里面的方法和属性来获取到页面需要操作的元素。当页面元素位置发生变化时,Page Object模式可以通过更改类的属性,不需要修改测试用例(参考百度)。以下将Page Object模式简称为PO模式。

二、PO模式有哪些优点

减少代码的编码量和维护量

清晰而明确的业务测试流程

使页面元素、元素操作和页面业务的分离

较少重复find click 样板代码,页面元素修改不影响测试用例

易读性提高

基本的实现逻辑:基于某个页面,操作某个元素,实现某个特定的功能

三、python+appium如何实现PO模式

Webdrive.Remote(url):链接server端,配置app的参数,实现启动和退出app

find_element_by_xxx:对元素定位方法封装

click/send_keys:对页面封装,操作元素、特定数据实现特定功能

testcase:测试用例封装,组合不同功能,实现某个特定的业务

四、例子

下面使用PO模式实现微博的账号密码登录,使用环境如下:

Java version: "1.8.0_241"

Python: 3.7.3

Node: v12.19.0

Appium: v1.18.3

PyCharm: Professional 2020.2

weibo: v10.11.3

测试框架:pytest

PO模式

框架:

1、init.py文件 — app参数配置,实现app的启动和退出

# 该类主要用于开启和退出app

from appium import webdriver

from page.login_page import LoginPage

class AppStart:

    # 声明driver对象

    driver: webdriver = None

    # 使用classmethod方法,可以直接调用类中的属性和函数

    @classmethod

    def start(cls):

        caps = {

"platformName": "Android",

                "deviceName": "U4AIUKFAL7W4MJLR",

                "platforVersion": "9",

                "appPackage": "com.sina.weibo",

                "appActivity": "com.sina.weibo.SplashActivity",

                "autoGrantPermissions": "true",

                "automationName": "UiAutomator2"

                }

        cls.driver = webdriver.Remote("<http://localhost:4723/wd/hub>", caps)

        cls.driver.implicitly_wait(20)

        return LoginPage(cls.driver)

    # 退出app

    @classmethod

    def quit(cls):

        cls.driver.quit()

注意:上述代码中设置的具体参数可以查找上一篇博客,博客地址为:https://www.jianshu.com/p/4f11290abe0d

2、base_page.py文件 — 基础类,用于封装元素定位操作

# 基础类,封装元素定位操作

from selenium.webdriver.remote.webdriver import WebDriver

class BasePage:

# 初始化,定义driver的类型为WebDriver

    def __init__(self, driver: WebDriver):

        self.driver = driver

    # 根据id定位

    def find_element(self, locator):

        try:

# 单个元素定位,获取到的是单个元素的位置

            return self.driver.find_element(*locator)

        except:

# 多个相同id元素定位,获取到的是一个列表,具体某个元素的位置可以使用列表查询

            return self.driver.find_elements(*locator)

    # 根据xpath定位

    def find_xpath(self, locator):

        try:

# 单个元素定位,获取到的是单个元素的位置

            return self.driver.find_element_by_xpath(locator)

        except:

# 多个相同xpath元素定位,获取到的是列表,具体某个元素的位置可以使用列表查询(xpath为唯一定位,一般不需要使用到该方法)

            return self.driver.find_elements(locator)

    # 根据classname定位

    def find_classname(self, *locator):

# classname定位使用较少,一般用于无法使用id定位和xpath定位时使用,获取到的是列表,具体某个元素的位置可以使用列表查询

        return self.driver.find_elements_by_class_name(*locator)

注意:

*locator:表示传入的参数数量是不固定的,可以传一个或多个参数

locator:表示传入的参数数量固定为一个

通过ID定位,传入的元素最少为两个,通过xpath和classname定位,传入的元素为一个

3、loge_page.py文件 — 欢迎页面操作

# 欢迎页相关操作

from appium import webdriver

from selenium.webdriver.common.by import By

from page.account_login_page import AccountLoginPage

from page.base_page import BasePage

# 继承BasePage类

class LoginPage(BasePage):

# 声明driver变量

    driver: webdriver = None

    # 隐私政策的同意按钮(根据xpath查找元素)

    _btn_agree = "/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.widget.LinearLayout/android.widget.TextView"

    # 账号密码登录按钮(根据id查找元素)

    _btn_account_pwd = (By.ID, "com.sina.weibo:id/tv_for_psw_login")

    # 进入账号密码登录页面

    def enter_account_login(self):

# 调用xpath元素定位方法,点击隐私政策同意按钮

        self.find_xpath(self._btn_agree).click()

# 调用id元素定位方法,进入账号密码登录页面

        self.find_element(self._btn_account_pwd).click()

        return AccountLoginPage(self.driver)

4、account_login_page.py文件 — 账号密码登录页面操作,主要内容为设置账号密码输入内容

# 账号密码登录页面相关操作

import time

from selenium.webdriver.common.by import By

from page.base_page import BasePage

# 继承BasePage类

class AccountLoginPage(BasePage):

    # 账号输入框

    _et_account = (By.ID, "com.sina.weibo:id/et_pws_username")

    # 密码输入框

    _et_pwd = (By.ID, "com.sina.weibo:id/et_pwd")

    # 登录按钮

    _btn_login = (By.ID, "com.sina.weibo:id/bn_pws_Login")

    # 手机号格式错误弹框的内容(底标为0),取消按钮(底标为2),弹框立即注册按钮或国际手机号登录按钮(底标为4)

    _tv_bounced_context = "android.widget.TextView"

    # 输入账号函数

    def input_account(self, account):

# 清空账号输入框内容

        self.find_element(self._et_account).clear()

# 账号输入框输入内容

        self.find_element(self._et_account).send_keys(account)

    # 输入密码函数

    def input_pwd(self, pwd):

# 清空密码输入框内容

        self.find_element(self._et_pwd).clear()

# 密码输入框输入内容

        self.find_element(self._et_pwd).send_keys(pwd)

    # 输入账号和密码函数

    def input_account_pwd(self, account, pwd):

# 调用输入账号函数

        self.input_account(account)

# 调用输入密码函数

        self.input_pwd(pwd)

# 点击登录密码

        self.find_element(self._btn_login).click()

    # 输入错误格式的手机号码获取弹框内容函数

    def get_bounced_context(self):

# 根据classname定位,将相同的classname元素存放在列表中

        bounced = self.find_classname(self._tv_bounced_context)

# 手机号码格式错误弹框内容再列表的第一位,列表的下表从0开始,并将弹框的内容定义为text属性

        bounced_context = bounced[0].text

        time.sleep(1)

# 输入账号密码后点击注册按钮,该按钮的位置在列表的第三位,故下标为2

        bounced[2].click()

# 将获取到的弹框内容返回,以便后续调用函数时能获取到弹框内容

        return bounced_context

5、account_login_testcase.py文件 — 账号密码登录测试用例

# 手机账号密码登录测试用例

from common.init import AppStart

class TestAccountLogin:

# 初始化

    def setup(self):

        self.accountloginpage = AppStart.start().enter_account_login()

    # 输入格式错误的账号

    def test_error_format_account(self):

# 设置输入的账号和密码

        account = "123123231321313"

        pwd = "asdfgh"

# 调用输入账号密码函数

        self.accountloginpage.input_account_pwd(account, pwd)

# 使用断言判断实际结果与预期结果是否一致,左边为实际结果,右边为预期结果

        assert self.accountloginpage.get_bounced_context() == "手机格式有问题,若非中国大陆手机号码请点击国际手机登录"

# 退出app

    def tearwodn(self):

        AppStart.quit()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343