PageObject+Python+Appium

目录

前言:

简介

功能

常用目录

配置

[实例 - 第一次启动 app](#实例 - 第一次启动 app)

[实例 - 登录](#实例 - 登录)

代码入口实例

结果展示


前言:

Page Object模式是一种常用的设计模式,用于组织和管理自动化测试脚本中的页面对象。它将页面的元素和操作封装在一个独立的类中,使测试脚本更加模块化、可维护和可重用。

简介

  • 基于 appium+python3 封装的自动化测试框架

功能

  • python3
  • unittest 参数化
  • pageobject
  • 数据维护用的 YMAL
  • excel 的测试报告
  • 支持多设备 andoird 并行
  • 支持 webview

常用目录

  • Base 封装常用方法
  • Log 记录不同设备的操作用例的日志,操作失败的截图
  • PageObject 放 page
  • test 目录写测试用例
  • runner 运行入口

配置

配置 run.yaml

复制代码
app: Jianshu.apk

配置 devices.yaml

复制代码
- devices:  emulator-5554
  port: 4724
  config: appium --session-override  -p 4724 -bp 4734 -U  emulator-5554
  platformName: android
- devices: DU2TAN15AJ049163
  port: 4725
  config: appium --session-override  -p 4725 -bp 4735 -U  DU2TAN15AJ049163
  platformName: android

实例 - 第一次启动 app

配置用例 yaml

复制代码
testinfo:
    - id: test001
      title: 第一次打开
testcase:
    - operate_type: swipeLeft
      time: 4
      element_info: android.widget.ImageView
      find_type: class_name
    - element_info: com.jianshu.haruki:id/tv_enter
      find_type: id
      operate_type: click
check:
    - element_info: com.jianshu.haruki:id/btn_login
      find_type: id

PageObject

复制代码
class FirstOpen:
    '''
    kwargs: WebDriver driver, String path(yaml配置参数)
    isOperate: 操作失败,检查点就失败
    testInfo:
    testCase:
    '''

    def __init__(self, **kwargs):
        self.driver = kwargs["driver"]
        self.path = kwargs["path"]
        self.operateElement = OperateElement(self.driver)
        self.isOperate = True
        self.testInfo = getYam(self.path)["testinfo"]
        self.testCase = getYam(self.path)["testcase"]


    '''
    操作步骤
    logTest 日记记录器
    '''

    def operate(self, logTest):
        for item in self.testCase:
            result = self.operateElement.operate(item, self.testInfo, logTest)

            if not result:
                print("操作失败")
                self.isOperate = False
                break

    '''
    检查点
    caseName:函数名
    logTest 记录日志:一个手机记录单独记录一个日志
    '''

    def checkPoint(self, caseName, logTest, devices):
        result = False
        if not self.isOperate:
            print("操作失败,检查点失败")
            # return self.isOperate
        else:
            check = getYam(self.path)["check"]
            result = self.operateElement.findElement(check)  # 检查点

        countSum(result)
        countInfo(result=result, testInfo=self.testInfo, caseName=caseName, driver=self.driver, logTest=logTest, devices=devices)
        return result

test

复制代码
PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p)
)


class FirstOpenTest(ParametrizedTestCase):
    def testFirst(self):
        firsOpen = FirstOpen(driver=self.driver, path=PATH("../yaml/firstOpen.yaml"))
        firsOpen.operate(logTest=self.logTest)
        firsOpen.checkPoint(caseName=self.__class__.__name__, logTest=self.logTest, devices=self.devices["deviceName"])


    def setUp(self):
        super(FirstOpenTest, self).setUp()

实例 - 登录

配置 yaml

复制代码
testinfo:
    - id: test0002
      title: 登录
testcase:
    - element_info: com.jianshu.haruki:id/btn_login
      find_type: id
      operate_type: click
    - element_info: com.jianshu.haruki:id/et_tel
      find_type: id
      operate_type: set_value
      text: username
    - element_info: com.jianshu.haruki:id/et_password
      find_type: id
      operate_type: set_value
      text: pwd
    - element_info: com.jianshu.haruki:id/btn_register_1
      find_type: id
      operate_type: click
    - element_info: //android.widget.ImageView[@index='0']
      find_type: xpath
      operate_type: click
check:
    - element_info: com.jianshu.haruki:id/add_subscribe
      find_type: id
    - element_info: com.jianshu.haruki:id/tab_more
      find_type: id

PageObject

复制代码
class Login:
    '''
    kwargs: WebDriver driver, String path(yaml配置参数)
    isOperate: 操作失败,检查点就失败
    testInfo:
    testCase:
    '''

    def __init__(self, **kwargs):
        self.driver = kwargs["driver"]
        self.path = kwargs["path"]
        self.operateElement = OperateElement(self.driver)
        self.isOperate = True
        self.testInfo = getYam(self.path)["testinfo"]
        self.testCase = getYam(self.path)["testcase"]

    '''
    操作步骤
     logTest 日记记录器
    '''

    def operate(self, logTest):
        for item in self.testCase:
            result = self.operateElement.operate(item, self.testInfo, logTest)

            if not result:
                print("操作失败")
                self.isOperate = False
                break
    '''
    检查点
    caseName:测试用例函数名 用作统计
    logTest: 日志记录
    devices 设备名
    '''

    def checkPoint(self, caseName, logTest, devices):
        result = False
        if not self.isOperate:
            print("操作失败,检查点失败")
        else:
            check = getYam(self.path)["check"]
            result = self.operateElement.findElement(check)  # 检查点

        countSum(result)
        countInfo(result=result, testInfo=self.testInfo, caseName=caseName, driver=self.driver, logTest=logTest, devices=devices)
        return result

test

复制代码
PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p)
)


class LoginTest(ParametrizedTestCase):

    def testLogin(self):
        login = Login(driver=self.driver, path=PATH("../yaml/login.yaml"))
        login.operate(logTest=self.logTest)
        login.checkPoint(caseName=self.__class__.__name__, logTest=self.logTest, devices=self.devices["deviceName"])

    # def testWrongPwd(self):
    #     pass

    def setUp(self):
        super(LoginTest, self).setUp()

代码入口实例

复制代码
def runnerCaseApp(devices):
    starttime = datetime.now()
    suite = unittest.TestSuite()
    suite.addTest(ParametrizedTestCase.parametrize(FirstOpenTest, param=devices)) # 引用不同的测试类
    suite.addTest(ParametrizedTestCase.parametrize(LoginTest, param=devices)) # 引用不同的测试类
    unittest.TextTestRunner(verbosity=2).run(suite)
    endtime = datetime.now()
    countDate(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str((endtime - starttime).seconds) + "秒"

    ...


if __name__ == '__main__':
    if AndroidDebugBridge().attached_devices():
        getDevices = init()
        appium_server = AppiumServer(getDevices)
        appium_server.start_server()
        while not appium_server.is_runnnig():
            time.sleep(2)
        runnerPool(getDevices)
        appium_server.stop_server()
        writeExcel()
    else:
        print(u"设备不存在")

结果展示

日志目录

文件夹:samsung_GT-I9500_android_4.4,包含截图

复制代码
2017-06-07 19:39:35,972  - INFO - ----  test001_第一次打开_android.widget.ImageView   START     ----
2017-06-07 19:39:44,433  - INFO - [CheckPoint_1]: FirstOpenTest: NG
2017-06-07 19:40:02,013  - INFO - ----  test0002_登录_com.jianshu.haruki:id/btn_login   START     ----
2017-06-07 19:40:03,075  - INFO - ----  test0002_登录_com.jianshu.haruki:id/et_tel   START     ----
2017-06-07 19:40:07,460  - INFO - ----  test0002_登录_com.jianshu.haruki:id/et_password   START     ----
2017-06-07 19:40:08,480  - INFO - ----  test0002_登录_com.jianshu.haruki:id/btn_register_1   START     ----
2017-06-07 19:40:13,640  - INFO - ----  test0002_登录_//android.widget.ImageView[@index='0']   START     ----

测试报告

作为一位过来人也是希望大家少走一些弯路

在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。

(软件测试相关资料,自动化测试相关资料,技术问题答疑等等)

相信能使你更好的进步!

点击下方小卡片

相关推荐
学测绘的小杨13 小时前
CompassFusion:一个从 GNSS 到 GNSS/INS 组合导航的独立工程包
python
zzzzzz31020 小时前
当产品经理说这个很简单:我用Python自动化处理奇葩需求的实战指南
python·pycharm·产品经理
雪隐20 小时前
个人电脑玩AI-06让5060 Ti给你打工——不光能画画,Qwen3-TTS还能学人说话,连我老板都信了!
人工智能·后端·python
兵慌码乱1 天前
面向桌面端的资产管理系统分层架构设计与核心模块实现
python·系统架构·sqlite·pyqt5·数据库设计·桌面应用开发·mvc架构
hboot1 天前
AI工程师第三课 - 机器学习基础
python·scikit-learn·kaggle
顾林海2 天前
Agent入门阶段-编程基础-Python:流程控制
python·agent·ai编程
呱呱复呱呱2 天前
Django CBV 源码解读:一个请求是怎么找到你的 get() 方法的
python·django
曲幽2 天前
刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API
python·fastapi·web·translate·goldendict·libretranslate·stardict·pystardict
荣码2 天前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
兵慌码乱2 天前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理