zoukankan      html  css  js  c++  java
  • Appium+unittest+PageObject自动化测试框架综合实践

    Appium自动化测试框架如下图:

    框架中包含的脚本以此如下展示:

    1.app目录下存放着测试需要的apk包

    2.baseView目录下脚本中封装着所有页面需要的方法

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-04 17:17
    # @Author : zhouyang
    # @File : baseView.py
    
    
    class BaseView(object):
        def __init__(self,driver):
            self.driver=driver
        def find_element(self,*loc):
            return self.driver.find_element(*loc)
        def find_elements(self,*loc):
            return self.driver.find_elements(*loc)
        def get_window_size(self):
            return self.driver.get_window_size()
        def swipe(self,start_x,start_y,end_x,end_y,duration):
            return self.driver.swipe(start_x,start_y,end_x,end_y,duration)

    3.businessView目录下存放着所有页面具体实现的方法,比如登录页面,注册页面

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-05 11:42
    # @Author : zhouyang
    # @File : loginView.py
    
    from common.desired_caps import appium_desired
    from common.commom_fun import Commom
    import logging
    from selenium.webdriver.common.by import By
    from selenium.common.exceptions import NoSuchElementException
    
    
    class LoginView(Commom):
        username_type=(By.ID,'com.tal.kaoyan:id/login_email_edittext')
        password_type=(By.ID,'com.tal.kaoyan:id/login_password_edittext')
        submit_type=(By.ID,'com.tal.kaoyan:id/login_login_btn')
    
        tip_commit=(By.ID,'com.tal.kaoyan:id/tip_commit')
    
        button_mysefl=(By.ID,'com.tal.kaoyan:id/mainactivity_button_mysefl')
        usercenter_username=(By.ID,'com.tal.kaoyan:id/activity_usercenter_username')
    
        RightButton_textview=(By.ID,'com.tal.kaoyan:id/myapptitle_RightButton_textview')
        logout_text=(By.ID,'com.tal.kaoyan:id/setting_logout_text')
    
    
        def login_action(self,username,password):
            self.check_cancleBtn()
            self.check_skipBtn()
            logging.info('=================login===================')
            logging.info('input username:%s'%username)
            self.driver.find_element(*self.username_type).send_keys(username)
    
            logging.info('input password:%s' %password)
            self.driver.find_element(*self.password_type).send_keys(password)
    
            logging.info('click loginBtn')
            self.driver.find_element(*self.submit_type).click()
            logging.info('===============login finish==============')
    
        def check_account_alert(self):
            logging.info('========check_account_alert==========')
            try:
                element=self.driver.find_element(*self.tip_commit)
            except NoSuchElementException:
                pass
            else:
                logging.info('=======close alert=======')
                element.click()
    
        def check_loginStatus(self):
            logging.info('======check_loginStatus======')
            self.check_market_ad()
            self.check_account_alert()
    
            try:
                self.driver.find_element(*self.button_mysefl).click()
                element=self.driver.find_element(*self.usercenter_username)
            except NoSuchElementException:
                logging.error('========login false=========')
                self.get_screenshot('login fail')
                return False
            else:
                logging.info('=========login success==========')
                self.logout_action()
                return True
    
        def logout_action(self):
            logging.info('=========logout action=========')
            self.driver.find_element(*self.RightButton_textview).click()
            self.driver.find_element(*self.logout_text).click()
            self.driver.find_element(*self.tip_commit).click()
    
    
    if __name__ == '__main__':
        driver=appium_desired()
        l=LoginView(driver)
        l.login_action('自学网2018','zxw208')
        l.check_loginStatus()
    
            
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-18 11:50
    # @Author : zhouyang
    # @File : register.py
    '''注册模块'''
    
    from common.commom_fun import Commom
    from common.desired_caps import appium_desired
    import logging
    from selenium.webdriver.common.by import By
    from selenium.common.exceptions import NoSuchElementException
    from random import randint
    
    class RegisterVeiw(Commom):
        register_text=(By.ID,'com.tal.kaoyan:id/login_register_text')
    
        register_userheader=(By.ID,'com.tal.kaoyan:id/activity_register_userheader')
        item_image=(By.ID,'com.tal.kaoyan:id/item_image')
        save=(By.ID,'com.tal.kaoyan:id/save')
    
        register_username=(By.ID,'com.tal.kaoyan:id/activity_register_username_edittext')
        register_password=(By.ID,'com.tal.kaoyan:id/activity_register_password_edittext')
        register_email=(By.ID,'com.tal.kaoyan:id/activity_register_email_edittext')
        register_btn=(By.ID,'com.tal.kaoyan:id/activity_register_register_btn')
    
        perfectinfomation_time=(By.ID,'com.tal.kaoyan:id/activity_perfectinfomation_time')
        text1=(By.ID,'android:id/text1')
    
        school_name=(By.ID,'com.tal.kaoyan:id/perfectinfomation_edit_school_name')
        forum_title=(By.ID,'com.tal.kaoyan:id/more_forum_title')
        university=(By.ID,'com.tal.kaoyan:id/university_search_item_name')
    
        perfectinfomation_major=(By.ID,'com.tal.kaoyan:id/activity_perfectinfomation_major')
        subject=(By.ID,'com.tal.kaoyan:id/major_subject_title')
        group=(By.ID,'com.tal.kaoyan:id/major_group_title')
        search_item=(By.ID,'com.tal.kaoyan:id/major_search_item_name')
    
        perfectinfomation_goBtn=(By.ID,'com.tal.kaoyan:id/activity_perfectinfomation_goBtn')
    
        button_mysefl = (By.ID, 'com.tal.kaoyan:id/mainactivity_button_mysefl')
        usercenter_username = (By.ID, 'com.tal.kaoyan:id/activity_usercenter_username')
    
    
        def register_action(self,username,password,email):
            logging.info('========register_action=========')
            self.check_cancleBtn()
            self.check_skipBtn()
            self.driver.find_element(*self.register_text).click() #点击注册
    
            #添加头像
            logging.info('set userheader')
            self.driver.find_element(*self.register_userheader).click()
            self.driver.find_elements(*self.item_image)[1].click()
            self.driver.find_element(*self.save).click()
    
            #填写用户名、密码、Email
            logging.info('username is %s'%username)
            self.driver.find_element(*self.register_username).send_keys(username)
    
            logging.info('password is %s' % password)
            self.driver.find_element(*self.register_password).send_keys(password)
    
            logging.info('email is %s' % email)
            self.driver.find_element(*self.register_email).send_keys(email)
    
            # 点击立即注册
            logging.info('register')
            self.driver.find_element(*self.register_btn).click()
    
            #判断是否进入注册信息页面
            try:
                self.driver.find_element(*self.perfectinfomation_time)
            except NoSuchElementException:
                logging.error('regiter fail')
                self.get_screenshot('regiter fail')
                return False
            else:
                self.add_register_info()
                if self.check_registerStatus():
                    return True
                else:
                    return False
    
        def add_register_info(self):
            logging.info('=======add_register_info=======')
            #填写年份
            self.driver.find_element(*self.perfectinfomation_time).click()
            self.driver.find_elements(*self.text1)[1].click() #2015
    
            #选择学校
            logging.info('select school')
            self.driver.find_element(*self.school_name).click()
            self.driver.find_elements(*self.forum_title)[1].click()
            self.driver.find_elements(*self.university)[1].click()
    
            #选择专业
            logging.info('select major')
            self.driver.find_element(*self.perfectinfomation_major).click()
            self.driver.find_elements(*self.subject)[1].click()
            self.driver.find_elements(*self.group)[2].click()
            self.driver.find_elements(*self.search_item)[0].click()
    
            #注册
            self.driver.find_element(*self.perfectinfomation_goBtn).click()
    
        def check_registerStatus(self):
            logging.info('========check_registerStatus==========')
            self.check_market_ad()
    
            try:
                self.driver.find_element(*self.button_mysefl).click()
                element = self.driver.find_element(*self.usercenter_username)
            except NoSuchElementException:
                logging.error('========register false=========')
                self.get_screenshot('register fail')
                return False
            else:
                logging.info('=========register success==========')
                return True
    
    if __name__ == '__main__':
        driver=appium_desired()
        r=RegisterVeiw(driver)
        username='zxw2000'+'fly'+str(randint(1000,9999))
        password='zxw2000'+str(randint(1000,9999))
        email='zxw2000'+str(randint(1000,9999))+'@163.com'
    
        r.register_action(username,password,email)

    4.common目录下存放着公共方法

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-04 17:22
    # @Author : zhouyang
    # @File : commom_fun.py
    
    from common.desired_caps import appium_desired
    from baseView.baseView import BaseView
    from selenium.common.exceptions import NoSuchElementException
    import logging,time,os,csv
    from selenium.webdriver.common.by import By
    
    class Commom(BaseView):
        cancelBtn=(By.ID,'android:id/button2')
        skipBtn=(By.ID,'com.tal.kaoyan:id/tv_skip')
    
        wemedia_cacel=(By.ID,'com.tal.kaoyan:id/view_wemedia_cacel')
    
        def check_cancleBtn(self):
            logging.info('===========check cancleBtn==========')
            try:
                cancelBtn = self.driver.find_element(*self.cancelBtn)
            except NoSuchElementException:
                logging.info('no cancelBtn')
            else:
                cancelBtn.click()
    
        def check_skipBtn(self):
            logging.info('===========check cancelBtn===========')
            try:
                skipBtn = self.driver.find_element(*self.skipBtn)
            except NoSuchElementException:
                logging.info('no cancelBtn')
            else:
                skipBtn.click()
    
        def get_size(self):
            x = driver.get_window_size()['width']
            y = driver.get_window_size()['height']
            return (x, y)
    
        def swipeLeft(self):
            l = self.get_size()
            x1 = int(l[0] * 0.9)
            x2 = int(l[0] * 0.1)
            y1 = int(l[1] * 0.5)
            driver.swipe(x1, y1, x2, y1, 1000)
    
        def getTime(self):
            self.now=time.strftime('%Y_%m_%d %H-%M-%S')
            return self.now
    
        def get_screenshot(self,module):
            time=self.getTime()
            image_file=os.path.dirname(os.path.dirname(__file__))+'/screenshot/%s_%s.png' %(module,time)
    
            logging.info('get %s screenshot'%module)
            self.driver.get_screenshot_as_file(image_file)
    
        def check_market_ad(self):
            logging.info('========check_market_ad=========')
            try:
                element=self.driver.find_element(*self.wemedia_cacel)
            except NoSuchElementException:
                pass
            else:
                logging.info('========close market========')
                element.click()
    
        def get_csv_data(self,csv_file,line):
            logging.info('======get_csv_data========')
            with open(csv_file,'r',encoding='utf-8-sig') as file:
                reader=csv.reader(file)
                for index,row in enumerate(reader,1):
                    if index==line:
                        return row
    
    
    
    
    if __name__ == '__main__':
        driver=appium_desired()
        com=Commom(driver)
        com.check_cancleBtn()
        com.check_skipBtn()
    
        # def get_csv_data(csv_file,line):
        #     with open(csv_file,'r',encoding='utf-8-sig') as file:
        #         reader=csv.reader(file)
        #         for index,row in enumerate(reader,1):
        #             if index==line:
        #                 return row
        #
        # csv_file='../data/account.csv'
        # data=get_csv_data(csv_file,1)
        # print(data)
    
        # lists=['这','是','一个','列表']
        # for index,row in enumerate(lists):
        #     print(index,row)
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-03 11:05
    # @Author : zhouyang
    # @File : capability_yaml.py
    '''
    从desired_caps.yaml文件中获取capability数据,登录考研帮app,把日志保存在文件中
    '''
    from appium import webdriver
    import yaml
    import logging
    import logging.config
    import os
    
    
    CON_LOG='../config/log.conf'
    logging.config.fileConfig(CON_LOG)
    logging=logging.getLogger()
    
    def appium_desired():
        with open('../config/desired_caps.yaml','r',encoding='utf-8') as file:
            data = yaml.load(file)
    
        desired_caps = {}
        desired_caps['platformName'] = data['platformName']
        desired_caps['platformVerion'] = data['platformVersion']
        desired_caps['deviceName'] = data['deviceName']
        #app使用相对路径
        base_dir = os.path.dirname(os.path.dirname(__file__))
        app_dir = os.path.join(base_dir, 'app', data['appname'])
        desired_caps['app'] = app_dir
    
        desired_caps['noReset'] = data['noReset']
        desired_caps['appPackage'] = data['appPackage']
        desired_caps['appActivity'] = data['appActivity']
        desired_caps['unicodeKeyboard'] = data['unicodeKeyboard']
        desired_caps['resetKeyboard'] = data['resetKeyboard']
    
        logging.info('start info...')
    
        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()
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-05 16:18
    # @Author : zhouyang
    # @File : myunit.py
    
    from common.desired_caps import appium_desired
    import logging
    import unittest
    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()

    5.config目录下存放所有配置文件,其中yaml文件中“:”后面一定要空一个格,否则会报错;.conf文件中内容,日志存放路径可以修改,日志表现形式等都可以修改

    desired_caps.yaml

    platformName: Android
    platformVersion: 4.4.2
    deviceName: 127.0.0.1:62001
    
    #真机
    #platformVersion: 4.4.2
    #udid:
    #deviceName: 127.0.0.1:62001
    appname: kaoyan3.1.0.apk
    appPackage: com.tal.kaoyan
    appActivity: com.tal.kaoyan.ui.activity.SplashActivity
    noReset: False
    unicodeKeyboard: True
    resetKeyboard: True
    ip: 127.0.0.1
    port: 4723

    log.conf

    [loggers]
    keys=root,infoLogger
    
    [logger_root]
    level=DEBUG
    handlers=consoleHandler,fileHandler
    
    [logger_infoLogger]
    handlers=consoleHandler,fileHandler
    qualname=infoLogger
    propagate=0
    
    [handlers]
    keys=consoleHandler,fileHandler
    
    [handler_consoleHandler]
    class=StreamHandler
    level=INFO
    formatter=form02
    args=(sys.stdout,)
    
    [handler_fileHandler]
    class=FileHandler
    level=INFO
    formatter=form01
    args=('../logs/runlog_conf.log', 'a')
    
    [formatters]
    keys=form01,form02
    
    [formatter_form01]
    format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
    
    [formatter_form02]
    format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s

    6.data目录中存放的是测试需要的数据,比如csv文件,Excel文件等

    7.logs目录下存放测试过程中产生的日志,存放目录和日志名及日志内容均取决于log.conf文件中的 

    args=('../logs/runlog_conf.log', 'a'),a表示追加,否则第二次执行测试后产生的日志会覆盖

    8.reports目录存放测试过程中产生的测试报告,测试报告的路径,名称,内容等都在run_test.py文件中定义

    9.screenshot目录存放测试过程中的截图,路径,名称等都取决于common目录下的common_fun.py文件下的get_screenshot()方法

    10.test_case目录下存放着所有的测试用例

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-05 16:24
    # @Author : zhouyang
    # @File : test_login.py
    '''
    unittest写的测试用例
    '''
    import unittest
    from common.myunit import StartEnd
    from businessView.loginView import LoginView
    import logging
    
    class Test_Login(StartEnd):
        def test_login_zxw2018(self):
            logging.info('=========test_login_zxw2018=========')
            l=LoginView(self.driver)
            l.login_action('自学网2018','zxw2018')
            self.assertTrue(l.check_loginStatus())
    
        def test_login_zxw2017(self):
            logging.info('=========test_login_zxw2017=========')
            l=LoginView(self.driver)
            l.login_action('自学网2017','zxw2017')
            self.assertTrue(l.check_loginStatus())
    
        def test_login_error(self):
            logging.info('=========test_login_error=========')
            l=LoginView(self.driver)
            l.login_action('123','456')
            self.assertTrue(l.check_loginStatus(),msg='login fail')
    
    if __name__ == '__main__':
        unittest.main()
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-22 16:32
    # @Author : zhouyang
    # @File : test_regiter.py
    '''注册测试用例'''
    
    from common.myunit import StartEnd
    from businessView.register import RegisterVeiw
    import logging
    from random import randint
    import unittest
    
    class RegisterTest(StartEnd):
    
        def test_user_register(self):
            logging.info('=======start regiter========')
            r = RegisterVeiw(self.driver)
            username = 'zxw2000' + 'fly' + str(randint(1000, 9999))
            password = 'zxw2000' + str(randint(1000, 9999))
            email = 'zxw2000' + str(randint(1000, 9999)) + '@163.com'
    
            self.assertTrue(r.register_action(username, password, email))
    
    if __name__ == '__main__':
        unittest.main()

    11.test_run目录下存放着run_test.py文件,用于执行测试,生成测试报告,也可以在里面添加发送邮件功能,生成的测试报告直接以邮件形式发送到邮箱

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2019-07-22 16:42
    # @Author : zhouyang
    # @File : run_test.py
    '''执行测试用例,生成测试报告'''
    
    import unittest
    import logging
    # from BSTestRunner import BSTestRunner
    from HTMLTestRunner import HTMLTestRunner
    import time
    
    #指定测试用例和测试报告的路径
    report_dir='../reports/'
    test_dir='../test_case'
    
    #加载测试用例
    discover=unittest.defaultTestLoader.discover(test_dir,pattern='test_login.py')
    
    #定义报告的文件格式
    now=time.strftime('%Y_%m_%d %H-%M-%S ')
    report_name=report_dir+now+'test_report.html'
    
    #运行用例并生成测试报告
    with open(report_name,'wb') as f:
        runner=HTMLTestRunner(stream=f,title=u'login test repotr',description=u'kyb login test report')
        logging.info('start run testcasse......')
        runner(discover)


  • 相关阅读:
    C字符串和C++字符串
    Linux的用户态和内核态
    知乎问答:如何理解“In UNIX, everything is a file”?
    科普:并行计算、分布式计算、集群计算和云计算
    个人使用VIM的一些总结
    C语言回调函数学习
    Python的函数参数传递:传值?引用?
    ECMAScript 函数函数概述
    ECMAScript 函数arguments 对象
    ECMAScript 语句with 语句
  • 原文地址:https://www.cnblogs.com/xiuxiu123456/p/11326113.html
Copyright © 2011-2022 走看看