Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场

系统 1448 0

简介

江湖有言:”代码写死一时爽,框架重构火葬场“,更有人戏言:”代码动态一时爽,一直动态一直爽“,虽然听起来有点耸人听闻,但也没有想象中的那么严重,我们在开发写代码的时候留心和注意就可以了。

为了重构时,少掉些头发,在开发的时候就得注意了。

 

写死代码后,有变动后出现bug后我们的反应

  Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第1张图片

大佬和菜鸟对遗留写死代码的反应

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第2张图片

最后和宏哥一起膜拜一下能够重构写死代码的大牛

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第3张图片

是不是有宏哥的风范啊

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第4张图片

闲话少说,进入今天的主题:PageObject+unittest。

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第5张图片

问题思考

前面我们都是基于线性模型来编写测试脚本,而且元素定位方式和属性值都是写死的。在业务场景简单的情况下这样写无可厚非,但是一旦遇到产品需求变更,业务逻辑比较复杂需要维护的时候就非常麻烦了,那么该如何应对这种情况呢?

场景案例

结合前面我们所学,测试考研帮 App登录场景,按照线性模型来构造出脚本如下: 考研帮登录测试场景

kyb_login.py

代码实现

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第6张图片

参考代码

            # coding=utf-
            
              8
            
            
              
# 
            
            
              1
            
            .先设置编码,utf-
            
              8可支持中英文,如上,一般放在第一行

# 
            
            
              2
            
            
              .注释:包括记录创建时间,创建人,项目名称。

            
            
              '''

            
            Created on 
            
              2019
            
            -
            
              8
            
            -
            
              16
            
            
              
@author: 北京
            
            -宏哥   QQ交流群:
            
              707699217
            
            
              
Project:学习和使用appium自动化测试
            
            -代码写死一时爽,框架重构火葬场 - PageObject+
            
              unittest

            
            
              '''

            
            # 
            
              3
            
            
              .导入模块

            
            
              from
            
            
               appium import webdriver
import yaml

            
            
              from
            
            
               selenium.common.exceptions import NoSuchElementException
import logging
import logging.config


CON_LOG
            
            =
            
              '
            
            
              ../log/log.conf
            
            
              '
            
            
              
logging.config.fileConfig(CON_LOG)
logging
            
            =
            
              logging.getLogger()


stream
            
            =open(
            
              '
            
            
              ../yaml/desired_caps.yaml
            
            
              '
            
            ,
            
              '
            
            
              r
            
            
              '
            
            
              )
data
            
            =
            
              yaml.load(stream)

desired_caps
            
            =
            
              {}
desired_caps[
            
            
              '
            
            
              platformName
            
            
              '
            
            ]=data[
            
              '
            
            
              platformName
            
            
              '
            
            
              ]

desired_caps[
            
            
              '
            
            
              platformVersion
            
            
              '
            
            ]=data[
            
              '
            
            
              platformVersion
            
            
              '
            
            
              ]
desired_caps[
            
            
              '
            
            
              deviceName
            
            
              '
            
            ]=data[
            
              '
            
            
              deviceName
            
            
              '
            
            
              ]

desired_caps[
            
            
              '
            
            
              app
            
            
              '
            
            ]=data[
            
              '
            
            
              app
            
            
              '
            
            
              ]
desired_caps[
            
            
              '
            
            
              noReset
            
            
              '
            
            ]=data[
            
              '
            
            
              noReset
            
            
              '
            
            
              ]

desired_caps[
            
            
              '
            
            
              unicodeKeyboard
            
            
              '
            
            ]=data[
            
              '
            
            
              unicodeKeyboard
            
            
              '
            
            
              ]
desired_caps[
            
            
              '
            
            
              resetKeyboard
            
            
              '
            
            ]=data[
            
              '
            
            
              resetKeyboard
            
            
              '
            
            
              ]

desired_caps[
            
            
              '
            
            
              appPackage
            
            
              '
            
            ]=data[
            
              '
            
            
              appPackage
            
            
              '
            
            
              ]
desired_caps[
            
            
              '
            
            
              appActivity
            
            
              '
            
            ]=data[
            
              '
            
            
              appActivity
            
            
              '
            
            
              ]

driver 
            
            = webdriver.Remote(
            
              '
            
            
              http://
            
            
              '
            
            +str(data[
            
              '
            
            
              ip
            
            
              '
            
            ])+
            
              '
            
            
              :
            
            
              '
            
            +str(data[
            
              '
            
            
              port
            
            
              '
            
            ])+
            
              '
            
            
              /wd/hub
            
            
              '
            
            
              , desired_caps)

def check_updateBtn():
    logging.info(
            
            
              "
            
            
              check_updateBtn
            
            
              "
            
            
              )

    
            
            
              try
            
            
              :
        element 
            
            = driver.find_element_by_id(
            
              '
            
            
              android:id/button2
            
            
              '
            
            
              )
    except NoSuchElementException:
        logging.info(
            
            
              '
            
            
              update element is not found!
            
            
              '
            
            
              )
    
            
            
              else
            
            
              :
        element.click()


def check_skipBtn():
    logging.info(
            
            
              "
            
            
              check_skipBtn
            
            
              "
            
            
              )
    
            
            
              try
            
            
              :
        element 
            
            = driver.find_element_by_id(
            
              '
            
            
              com.tal.kaoyan:id/tv_skip
            
            
              '
            
            
              )
    except NoSuchElementException:
        logging.info(
            
            
              '
            
            
              skipBtn element is not found!
            
            
              '
            
            
              )
    
            
            
              else
            
            
              :
        element.click()

check_updateBtn()
check_skipBtn()

logging.info(
            
            
              '
            
            
              start login...
            
            
              '
            
            
              )

driver.find_element_by_id(
            
            
              '
            
            
              com.tal.kaoyan:id/login_email_edittext
            
            
              '
            
            ).send_keys(
            
              '
            
            
              自学网2018
            
            
              '
            
            
              )
driver.find_element_by_id(
            
            
              '
            
            
              com.tal.kaoyan:id/login_password_edittext
            
            
              '
            
            ).send_keys(
            
              '
            
            
              zxw2018
            
            
              '
            
            
              )
driver.find_element_by_id(
            
            
              '
            
            
              com.tal.kaoyan:id/login_login_btn
            
            
              '
            
            
              ).click()
logging.info(
            
            
              '
            
            
              login finished
            
            
              '
            
            )
          

案例分析

上面的脚本看似都比较完善,有了 log采集,参数配置、启动时页面元素自动检测。但是也存在一些不足之处:

  • 公共模块和业务模块混合在一起显得代码冗余等
  • 测试场景单一(如果要实现如下测试场景该怎么办?)
  • 元素定位属性和代码混杂在一起

以上这些都是需要优化的地方。

测试场景

操作步骤

预期结果

多账号登录

不同的用户名密码来进行登录

能够正常登录

异常登录

用户名或者密码错误、或者为空进行登录,

登录失败,同时界面要给出相应的提示

注册

点击注册,然后进行注册信息填写

能够注册成功

重构优化思路

  • 将一些公共的内容(如: check_updateBtn,check_skipBtn,capability)抽离出来。
  • 元素定位方法和元素属性值与业务代码分离
  • 登录功能模块封装为一个独立的模块
  • 使用 unittest进行用例综合管理

Page Object

Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高测试用例的可维护性。

脚本实现

封装 App启动配置信息

desired_caps.py

代码实现

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第7张图片

参考代码

            # coding=utf-
            
              8
            
            
              
# 
            
            
              1
            
            .先设置编码,utf-
            
              8可支持中英文,如上,一般放在第一行

# 
            
            
              2
            
            
              .注释:包括记录创建时间,创建人,项目名称。

            
            
              '''

            
            Created on 
            
              2019
            
            -
            
              8
            
            -
            
              16
            
            
              
@author: 北京
            
            -宏哥   QQ交流群:
            
              707699217
            
            
              
Project:学习和使用appium自动化测试
            
            -代码写死一时爽,框架重构火葬场 - PageObject+
            
              unittest

            
            
              '''

            
            # 
            
              3
            
            
              .导入模块

            
            
              from
            
            
               appium import webdriver
import yaml
import logging
import logging.config

CON_LOG
            
            =
            
              '
            
            
              ../log/log.conf
            
            
              '
            
            
              
logging.config.fileConfig(CON_LOG)
logging
            
            =
            
              logging.getLogger()

def appium_desired():
    file 
            
            = open(
            
              '
            
            
              ../yaml/desired_caps.yaml
            
            
              '
            
            , 
            
              '
            
            
              r
            
            
              '
            
            
              )
    data 
            
            =
            
               yaml.load(file)

    desired_caps
            
            =
            
              {}
    desired_caps[
            
            
              '
            
            
              platformName
            
            
              '
            
            ]=data[
            
              '
            
            
              platformName
            
            
              '
            
            
              ]
    desired_caps[
            
            
              '
            
            
              platformVersion
            
            
              '
            
            ]=data[
            
              '
            
            
              platformVersion
            
            
              '
            
            
              ]
    desired_caps[
            
            
              '
            
            
              deviceName
            
            
              '
            
            ]=data[
            
              '
            
            
              deviceName
            
            
              '
            
            
              ]

    desired_caps[
            
            
              '
            
            
              app
            
            
              '
            
            ]=data[
            
              '
            
            
              app
            
            
              '
            
            
              ]
    desired_caps[
            
            
              '
            
            
              appPackage
            
            
              '
            
            ]=data[
            
              '
            
            
              appPackage
            
            
              '
            
            
              ]
    desired_caps[
            
            
              '
            
            
              appActivity
            
            
              '
            
            ]=data[
            
              '
            
            
              appActivity
            
            
              '
            
            
              ]
    desired_caps[
            
            
              '
            
            
              noReset
            
            
              '
            
            ]=data[
            
              '
            
            
              noReset
            
            
              '
            
            
              ]

    desired_caps[
            
            
              '
            
            
              unicodeKeyboard
            
            
              '
            
            ]=data[
            
              '
            
            
              unicodeKeyboard
            
            
              '
            
            
              ]
    desired_caps[
            
            
              '
            
            
              resetKeyboard
            
            
              '
            
            ]=data[
            
              '
            
            
              resetKeyboard
            
            
              '
            
            
              ]

    logging.info(
            
            
              '
            
            
              start app...
            
            
              '
            
            
              )
    driver
            
            =webdriver.Remote(
            
              '
            
            
              http://
            
            
              '
            
            +str(data[
            
              '
            
            
              ip
            
            
              '
            
            ])+
            
              '
            
            
              :
            
            
              '
            
            +str(data[
            
              '
            
            
              port
            
            
              '
            
            ])+
            
              '
            
            
              /wd/hub
            
            
              '
            
            
              ,desired_caps)
    driver.implicitly_wait(
            
            
              8
            
            
              )
    
            
            
              return
            
            
               driver


            
            
              if
            
             __name__ == 
            
              '
            
            
              __main__
            
            
              '
            
            
              :
    appium_desired()
            
          

记得在原来的 yaml配置表desired_caps.yaml补充如下内容:

unicodeKeyboard: True 

resetKeyboard: True

封装基类: 

baseView.py

代码实现

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第8张图片

参考代码

            # coding=utf-
            
              8
            
            
              
# 
            
            
              1
            
            .先设置编码,utf-
            
              8可支持中英文,如上,一般放在第一行

# 
            
            
              2
            
            
              .注释:包括记录创建时间,创建人,项目名称。

            
            
              '''

            
            Created on 
            
              2019
            
            -
            
              8
            
            -
            
              16
            
            
              
@author: 北京
            
            -宏哥   QQ交流群:
            
              707699217
            
            
              
Project:学习和使用appium自动化测试
            
            -代码写死一时爽,框架重构火葬场 - PageObject+
            
              unittest

            
            
              '''

            
            # 
            
              3
            
            
              .定义类

            
            
              class
            
             BaseView(
            
              object
            
            
              ):
    def __init__(self,driver):
        self.driver
            
            =
            
              driver

    def find_element(self,
            
            *
            
              loc):
        
            
            
              return
            
             self.driver.find_element(*loc)
          

封装通用公共类

common_fun.py

代码实现

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第9张图片

参考代码

            # coding=utf-
            
              8
            
            
              
# 
            
            
              1
            
            .先设置编码,utf-
            
              8可支持中英文,如上,一般放在第一行

# 
            
            
              2
            
            
              .注释:包括记录创建时间,创建人,项目名称。

            
            
              '''

            
            Created on 
            
              2019
            
            -
            
              8
            
            -
            
              16
            
            
              
@author: 北京
            
            -宏哥   QQ交流群:
            
              707699217
            
            
              
Project:学习和使用appium自动化测试
            
            -代码写死一时爽,框架重构火葬场 - PageObject+
            
              unittest

            
            
              '''

            
            # 
            
              3
            
            
              .导入模块

            
            
              from
            
            
               page_object.baseView import BaseView

            
            
              from
            
            
               page_object.desired_caps import appium_desired

            
            
              from
            
            
               selenium.common.exceptions import NoSuchElementException
import logging

            
            
              from
            
            
               selenium.webdriver.common.by import By


            
            
              class
            
            
               Common(BaseView):
    cancelBtn
            
            =(By.ID,
            
              '
            
            
              android:id/button2
            
            
              '
            
            
              )
    skipBtn
            
            =(By.ID,
            
              '
            
            
              com.tal.kaoyan:id/tv_skip
            
            
              '
            
            
              )

    def check_cancelBtn(self):
        logging.info(
            
            
              '
            
            
              ==========check_cancelBtn=========
            
            
              '
            
            
              )
        
            
            
              try
            
            
              :
            cancelBtn 
            
            = self.driver.find_element(*
            
              self.cancelBtn)
        except NoSuchElementException:
            logging.info(
            
            
              '
            
            
              no cancelBtn
            
            
              '
            
            
              )
        
            
            
              else
            
            
              :
            cancelBtn.click()

    def check_skipBtn(self):
        logging.info(
            
            
              '
            
            
              =========check skipBtn=============
            
            
              '
            
            
              )

        
            
            
              try
            
            
              :
            skipBtn 
            
            = self.driver.find_element(*
            
              self.skipBtn)
        except NoSuchElementException:
            logging.info(
            
            
              '
            
            
              no skipBtn
            
            
              '
            
            
              )
        
            
            
              else
            
            
              :
            skipBtn.click()


            
            
              if
            
             __name__ == 
            
              '
            
            
              __main__
            
            
              '
            
            
              :
    driver
            
            =
            
              appium_desired()
    com
            
            =
            
              Common(driver)
    com.check_cancelBtn()
    com.check_skipBtn()
            
          

封装登录操作 

loginView.py

代码实现

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第10张图片

参考代码

            # coding=utf-
            
              8
            
            
              
# 
            
            
              1
            
            .先设置编码,utf-
            
              8可支持中英文,如上,一般放在第一行

# 
            
            
              2
            
            
              .注释:包括记录创建时间,创建人,项目名称。

            
            
              '''

            
            Created on 
            
              2019
            
            -
            
              8
            
            -
            
              16
            
            
              
@author: 北京
            
            -宏哥   QQ交流群:
            
              707699217
            
            
              
Project:学习和使用appium自动化测试
            
            -代码写死一时爽,框架重构火葬场 - PageObject+
            
              unittest

            
            
              '''

            
            # 
            
              3
            
            
              .导入模块
import logging

            
            
              from
            
            
               page_object.common_fun import Common

            
            
              from
            
            
               page_object.desired_caps import appium_desired

            
            
              from
            
            
               selenium.webdriver.common.by import By


            
            
              class
            
            
               LoginView(Common):
    username_type
            
            =(By.ID,
            
              '
            
            
              com.tal.kaoyan:id/login_email_edittext
            
            
              '
            
            
              )
    password_type
            
            =(By.ID,
            
              '
            
            
              com.tal.kaoyan:id/login_password_edittext
            
            
              '
            
            
              )
    loginBtn
            
            =(By.ID,
            
              '
            
            
              com.tal.kaoyan:id/login_login_btn
            
            
              '
            
            
              )

    def login_action(self,username,password):
        self.check_cancelBtn()
        self.check_skipBtn()

        logging.info(
            
            
              '
            
            
              ============login_action==============
            
            
              '
            
            
              )
        logging.info(
            
            
              '
            
            
              username is:%s
            
            
              '
            
             %
            
              username)
        self.driver.find_element(
            
            *
            
              self.username_type).send_keys(username)

        logging.info(
            
            
              '
            
            
              password is:%s
            
            
              '
            
            %
            
              password)
        self.driver.find_element(
            
            *
            
              self.password_type).send_keys(password)

        logging.info(
            
            
              '
            
            
              click loginBtn
            
            
              '
            
            
              )
        self.driver.find_element(
            
            *
            
              self.loginBtn).click()
        logging.info(
            
            
              '
            
            
              login finished!
            
            
              '
            
            
              )


            
            
              if
            
             __name__ == 
            
              '
            
            
              __main__
            
            
              '
            
            
              :
    driver
            
            =
            
              appium_desired()
    l
            
            =
            
              LoginView(driver)
    l.login_action(
            
            
              '
            
            
              北京-宏哥-2019
            
            
              '
            
            ,
            
              '
            
            
              bjhg2019
            
            
              '
            
            )
          

unittest用例封装

测试场景

使用如下账号进行分别登录测试

用户名

密码

自学网2018

zxw2018

自学网2017

zxw2017

666

222

Tips必备基础知识: Selenium自动化第六章-unittest单元测试框架

1.封装用例启动结束时的配置: 

myunit.py

代码实现

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第11张图片

参考代码

            # coding=utf-
            
              8
            
            
              
# 
            
            
              1
            
            .先设置编码,utf-
            
              8可支持中英文,如上,一般放在第一行

# 
            
            
              2
            
            
              .注释:包括记录创建时间,创建人,项目名称。

            
            
              '''

            
            Created on 
            
              2019
            
            -
            
              8
            
            -
            
              16
            
            
              
@author: 北京
            
            -宏哥   QQ交流群:
            
              707699217
            
            
              
Project:学习和使用appium自动化测试
            
            -代码写死一时爽,框架重构火葬场 - PageObject+
            
              unittest

            
            
              '''

            
            # 
            
              3
            
            
              .导入模块
import unittest

            
            
              from
            
            
               page_object.desired_caps import appium_desired
import logging

            
            
              from
            
            
               time import sleep


            
            
              class
            
            
               StartEnd(unittest.TestCase):
    def setUp(self):
        logging.info(
            
            
              '
            
            
              =====setUp====
            
            
              '
            
            
              )
        self.driver
            
            =
            
              appium_desired()

    def tearDown(self):
        logging.info(
            
            
              '
            
            
              ====tearDown====
            
            
              '
            
            
              )
        sleep(
            
            
              5
            
            
              )
        self.driver.close_app()
            
          

2.用例封装 

test_login.py

代码实现

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第12张图片

参考代码

            # coding=utf-
            
              8
            
            
              
# 
            
            
              1
            
            .先设置编码,utf-
            
              8可支持中英文,如上,一般放在第一行

# 
            
            
              2
            
            
              .注释:包括记录创建时间,创建人,项目名称。

            
            
              '''

            
            Created on 
            
              2019
            
            -
            
              8
            
            -
            
              16
            
            
              
@author: 北京
            
            -宏哥   QQ交流群:
            
              707699217
            
            
              
Project:学习和使用appium自动化测试
            
            -代码写死一时爽,框架重构火葬场 - PageObject+
            
              unittest

            
            
              '''

            
            # 
            
              3
            
            
              .导入模块

            
            
              from
            
            
               unittest.myunit import StartEnd

            
            
              from
            
            
               page_object.loginView import LoginView
import unittest
import logging


            
            
              class
            
            
               TestLogin(StartEnd):

    def test_login_bjhg2019(self):
        logging.info(
            
            
              '
            
            
              ======test_login_bjhg-2019=====
            
            
              '
            
            
              )
        l
            
            =
            
              LoginView(self.driver)
        l.login_action(
            
            
              '
            
            
              北京宏哥-2018
            
            
              '
            
            ,
            
              '
            
            
              bjhg-2019
            
            
              '
            
            
              )

    def test_login_bjhg2018(self):
        logging.info(
            
            
              '
            
            
              ======test_login_bjhg-2018=====
            
            
              '
            
            
              )
        l
            
            =
            
              LoginView(self.driver)
        l.login_action(
            
            
              '
            
            
              北京宏哥-2018
            
            
              '
            
            ,
            
              '
            
            
              bjhg-2018
            
            
              '
            
            
              )

    def test_login_error(self):
        logging.info(
            
            
              '
            
            
              ======test_login_error=====
            
            
              '
            
            
              )
        l 
            
            =
            
               LoginView(self.driver)
        l.login_action(
            
            
              '
            
            
              6666
            
            
              '
            
            , 
            
              '
            
            
              222
            
            
              '
            
            
              )


            
            
              if
            
             __name__ == 
            
              '
            
            
              __main__
            
            
              '
            
            
              :
    unittest.main()
            
          

小结

1.代码运行流程图

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第13张图片

 

 2.宏哥箴言:

代码写死一时爽,框架重构火葬场。此处功能将来必改,不要写死!

  Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第14张图片

 3.最后大家要且行且珍惜,出来混迟早晚要还的。 ( ^__^ ) 嘻嘻……

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第15张图片

 

您的肯定就是我进步的动力。 如果你感觉还不错,就请鼓励一下吧!记得点波  推荐  哦!!! (点击右边的小球即可!( ^__^ ) 嘻嘻……)

 

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第16张图片


.

       个人公众号                                                              微信群  (微信群已满100,可以加宏哥的微信拉你进群,请备注:进群)          

Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第17张图片                                                                   Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)_第18张图片


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论