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)


  • 相关阅读:
    zoj 3627#模拟#枚举
    Codeforces 432D Prefixes and Suffixes kmp
    hdu 4778 Gems Fight! 状压dp
    CodeForces 379D 暴力 枚举
    HDU 4022 stl multiset
    手动转一下田神的2048
    【ZOJ】3785 What day is that day? ——KMP 暴力打表找规律
    poj 3254 状压dp
    C++中运算符的优先级
    内存中的数据对齐
  • 原文地址:https://www.cnblogs.com/xiuxiu123456/p/11326113.html
Copyright © 2011-2022 走看看