PageObject+Python+Appium开源分享

作者: 望月成三人 | 来源:发表于2017-06-08 09:14 被阅读359次

    之前发过一篇帖子开源框架 appium+python

    此次主要大改了一次,代码和框架,去掉了监控闪退和性能测试监控

    简介

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

    功能

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

    常用目录

    • 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     ----
    

    测试报告

    Paste_Image.png Paste_Image.png

    开源地址点击查看

    相关文章

      网友评论

      • barryli89:楼主 我按你的代码都成功跑起来了,
        然后有几点疑问,
        测试之前的setup步骤也要单独写成一个脚本去调?
        还有一个yaml里面只能有一个用例?我追加了一个后就报错了
        barryli89:@望月成三人 对了 楼主你们做UI自动化的时候 对面目上展现的数据怎么校验呢 数据库查?
        望月成三人:理论上是一个yaml一个用例,就像写测试用例一样~你可以在test里面,写多个测试步骤,只要指定不同的yaml就行了
      • 古佛青灯度流年:Unittest 的suite 极其之恶心,建议你要不自己封装用discover 的形式,要不就干脆用nose,我有直接封装好的欢迎品尝:smile:
        古佛青灯度流年:@望月成三人 说反了,我也用的unittest.,只是封装的discover 形式,比较简单
        望月成三人:一直在用unittest,不怎么熟悉nose,麻烦把你封装好的东西地址发我下,我尝尝:smile:

      本文标题:PageObject+Python+Appium开源分享

      本文链接:https://www.haomeiwen.com/subject/ndezfxtx.html