[python]appium+pytest+allure移动端自动化(二)框架篇

目录

  • 1 项目实例
  • 2 必备信息统计
    • 2.1 查看要测试的apk的信息
    • 2.2 查看模拟器地址、系统版本号
    • 2.3 启动appium,并查看appium端口号
  • 3 开始搭架子
  • 4 开始写
    • 4.1 先写一个简单的demo
    • 4.2 开始封装
      • 4.2.1 封装PageObject
      • 4.2.2 日志封装
    • 4.3 写个测试用例测试下
    • 4.4 生成个报告

1 项目实例

框架如下:
[python]appium+pytest+allure移动端自动化(二)框架篇_第1张图片

2 必备信息统计

2.1 查看要测试的apk的信息

aapt dump badging xxx.apk

下图中框起来的即为appPackage
[python]appium+pytest+allure移动端自动化(二)框架篇_第2张图片
往下拉,找到launchable-activity,即为appActivity
[python]appium+pytest+allure移动端自动化(二)框架篇_第3张图片

2.2 查看模拟器地址、系统版本号

adb devices #查看模拟器地址

在这里插入图片描述
系统版本号:
在模拟器中“设置-关于”中查看
[python]appium+pytest+allure移动端自动化(二)框架篇_第4张图片

2.3 启动appium,并查看appium端口号

appium

在这里插入图片描述

3 开始搭架子

IDE:我用的vscode,推荐使用pycharm

我们采用page object的架构

建个工程,叫appium
建几个二级文件夹 case、pages、util、log、result、report、log
顾名思义:
case 存放测试用例
pages 存放页面对象、方法
util 存放工具类,如日志
log 存放日志
result 存放测试结果,allure生成报告需要的测试结果
report 存放生成的allure测试报告
log 存放日志
注:建二级子目录后,pycharm会自动添加__init__.py,但是vscode不会,我们需要在case、pages、util目录下手动添加__init__.py

4 开始写

4.1 先写一个简单的demo

目的:这个demo的实现启动app、点击或者滑动一下

case目录下创建demo.py,键入如下内容:

# -*- encoding: utf-8 -*-
from appium import webdriver
import time

# apk参数
desired_caps = {
    'platformName': 'Android',
    'deviceName': '127.0.0.1:62001',  # 手机设备名称,通过adb devices查看
    'platformVersion': '5.1.1',  # android系统的版本号
    'appPackage': 'com.aiosign.dzonesign',  # apk包名
    # apk的launcherActivity
    'appActivity': 'com.aiosign.dzonesign.view.AppStartActivity',
}
# 启动app
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
time.sleep(3)
# 我的app启动后是欢迎页,需要滑动
# 获取屏幕尺寸
sizes = driver.get_window_size()
# 滑动
driver.swipe(sizes.get('width')*0.9, sizes.get('height')*0.5, sizes.get('width')*0.2, sizes.get('height')*0.5)

运行代码,看一下:
[python]appium+pytest+allure移动端自动化(二)框架篇_第5张图片

4.2 开始封装

4.2.1 封装PageObject

整个应用大概分为这么几个页面:

  • 欢迎页
  • 登录页
  • 主页

所以,我们在pages目录下创建一个BasePage.py用来存放一些公用的方法,比如查找元素、查找一组元素、输入、左右上下滑动、截图等

再创建三个py文件分别为WelcomePage.py LoginPage.py MainPage.py,继承自BasePage.py,如下:
[python]appium+pytest+allure移动端自动化(二)框架篇_第6张图片
BasePage.py内容如下:

# -*- encoding: utf-8 -*-
'''
@File    :   BasePage.py
@Time    :   2020/02/11 14:49:52
@Author  :   peace_su
@Version :   1.0
@Contact :   [email protected]
@WebSite :   https://me.csdn.net/u010098760
'''

# here put the import lib
from selenium.webdriver.support.wait import WebDriverWait
# from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
import time
from util.LoggingUtil import LoggingUtil
import logging
import datetime


class BasePage(object):
    '''类注释
    详细描述

    Attributes:
        属性说明
    '''

    def __init__(self, driver):
        '''Class1类初始化方法

        Args:
            paramter1: 入参说明
            paramter2: 入参说明
        '''
        self.driver = driver
        LoggingUtil.setup_logging(LoggingUtil)
        self.logger = logging.getLogger()

    def find_element(self, *loc):
        '''重写查找单个元素方法

        '''
        try:
            WebDriverWait(self.driver, 5, 0.5).until(
                EC.visibility_of_element_located(loc))
            return self.driver.find_element(*loc)
        except Exception:
            # print('页面未找到元素')
            self.logger.error('未找到元素:%s 请检查!' % loc[1])
            screen_shot = self.get_screen('screen_shot/')
            self.logger.error('已截图,路径:%s' % screen_shot)

    def find_elements(self, *loc):
        '''重写查找多个元素方法

        '''
        try:
            WebDriverWait(self.driver, 5, 0.5).until(
                EC.visibility_of_element_located(loc))
            return self.driver.find_elements(*loc)
        except AttributeError:
            # print('页面未找到元素')
            self.logger.error('未找到元素:%s 请检查!' % loc[1])
            screen_shot = self.get_screen('screen_shot/')
            self.logger.error('已截图,路径:%s' % screen_shot)

    def send_keys(self, loc, vaule, clear_first=True, click_first=True):
        '''重写send_keys方法

        '''
        try:
            loc = getattr(self, "_%s" % loc)  # getattr相当于实现self.loc
            if click_first:
                self.find_element(*loc).click()
            if clear_first:
                self.find_element(*loc).clear()
                self.find_element(*loc).send_keys(vaule)
        except AttributeError:
            # print("页面中未能找到元素")
            self.logger.error('未找到元素:%s 请检查!' % loc[1])
            screen_shot = self.get_screen('screen_shot/')
            self.logger.error('已截图,路径:%s' % screen_shot)

    def is_toast_exist(self, text):
        '''is toast exist, return True or False
        :Agrs:
            - text   - 页面上看到的文本内容
        :Usage:
            is_toast_exist("看到的内容")
        '''
        try:
            toast_loc = (By.XPATH, ".//*[contains(@text,'%s')]" % text)
            WebDriverWait(self.driver, 5, 0.5).until(
                EC.presence_of_element_located(toast_loc))
            return True
        except Exception as e:
            print(e)
            self.logger.error('未找到元素:%s 请检查!' % text)
            screen_shot = self.get_screen('screen_shot/')
            self.logger.error('已截图,路径:%s' % screen_shot)
            return False

    def is_element_exist(self, *loc):
        try:
            WebDriverWait(self.driver, 5, 0.5).until(
                EC.visibility_of_element_located(loc))
            self.driver.find_element(*loc)
            return True
        except Exception:
            # print('页面未找到%s元素' % (loc))
            self.logger.error('未找到元素:%s 请检查!' % loc[1])
            screen_shot = self.get_screen('screen_shot/')
            self.logger.error('已截图,路径:%s' % screen_shot)
            return False

    def get_size(self):
        '''获取屏幕大小

        '''
        try:
            size = self.driver.get_window_size()
            return size
        except Exception:
            self.get_screen('screen_shot/')
            return None

    def swipe_to_left(self):
        '''左滑

        '''
        window_size = self.get_size()
        width = window_size.get("width")
        height = window_size.get("height")
        try:
            self.driver.swipe(width*0.9, height*0.5, width*0.1, height*0.5)
            time.sleep(0.5)
        except Exception:
            self.get_screen('screen_shot/')
        # self.driver.swipe(x*0.9, y*0.5, x*0.1, y*0.5)

    def swipe_to_right(self):
        '''右滑

        '''
        window_size = self.get_size()
        width = window_size.get("width")
        height = window_size.get("height")
        try:
            self.driver.swipe(width*0.1, height*0.5, width*0.9, height*0.5)
            time.sleep(0.5)
        except Exception:
            self.get_screen('screen_shot/')

    def swipe_to_up(self):
        '''上滑

        '''
        window_size = self.get_size()
        width = window_size.get("width")
        height = window_size.get("height")
        try:
            self.driver.swipe(width*0.5, height*0.9, width*0.5, height*0.1)
            time.sleep(0.5)
        except Exception:
            self.get_screen('screen_shot/')

    def swipe_to_down(self):
        '''下滑、下拉刷新

        '''
        window_size = self.get_size()
        width = window_size.get("width")
        height = window_size.get("height")
        try:
            self.driver.swipe(width*0.5, height*0.4, width*0.5, height*0.9)
            time.sleep(1)
        except Exception:
            self.get_screen('screen_shot/')

    def get_screen(self, path):
        '''截图

        '''
        now = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        screen_shot = path + 'a_' + now + '.png'
        self.driver.get_screenshot_as_file(screen_shot)
        return screen_shot


if __name__ == '__main__':
    print(123)

WelcomePage.py内容如下:

# -*- encoding: utf-8 -*-
'''
@File    :   WelcomePage.py
@Time    :   2020/02/11 14:49:29
@Author  :   peace_su
@Version :   1.0
@Contact :   [email protected]
@WebSite :   https://me.csdn.net/u010098760
'''

# here put the import lib
from selenium.webdriver.common.by import By
from pages.BasePage import BasePage


class WelcomePage(BasePage):
    '''欢迎页面元素及方法
        该类继承自BasePage类

    Attributes:
        属性说明
    '''
    # 立即体验 按钮
    tiyan_button = (By.ID, 'com.aiosign.dzonesign:id/vStartNow')

    # 登录 按钮
    login_button = (By.ID, 'com.aiosign.dzonesign:id/btLoginUser')

    # 注册 按钮
    register_button = (By.ID, 'com.aiosign.dzonesign:id/btRegisterUser')

    # 点击立即体验按钮
    def click_tiyan_button(self):
        self.find_element(*self.tiyan_button).click()

    # 点击登录按钮
    def click_login_button(self):
        self.find_element(*self.login_button).click()

    # 点击注册按钮
    def click_register_button(self):
        self.find_element(*self.register_button).click()


if __name__ == '__main__':
    print(123)

LoginPage 和 MainPage内容略过

4.2.2 日志封装

暂时略过

4.3 写个测试用例测试下

单元测试使用pytest
unittest无法集成allure,htmltestrunner的日志太难看了

在case目录下建个test_login.py,如下:

# -*- encoding: utf-8 -*-
'''
@File    :   test_login.py
@Time    :   2020/03/05 14:28:40
@Author  :   peace_su
@Version :   1.0
@Contact :   [email protected]
@WebSite :   https://me.csdn.net/u010098760
'''

# here put the import lib
import sys
import os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)

import pytest
from util.LoggingUtil import LoggingUtil
from pages.BasePage import BasePage
from pages.WelcomePage import WelcomePage
from pages.LoginPage import LoginPage
from pages.MainPage import MainPage
import logging
from appium import webdriver
import time
import allure


@allure.feature('测试登录功能')
class Test_login(object):
    '''类注释
    详细描述

    Attributes:
        属性说明
    '''

    def setup_method(self, method):
        self.logging_util = LoggingUtil()
        self.logging_util.setup_logging()
        self.logger = logging.getLogger()
        desired_caps = {
            'platformName': 'Android',
            # 'deviceName': '127.0.0.1:5554',  # 手机设备名称,通过adb devices查看
            'deviceName': '127.0.0.1:62001',  # 手机设备名称,通过adb devices查看
            'platformVersion': '5.1.1',  # android系统的版本号
            'appPackage': 'com.aiosign.dzonesign',  # apk包名
            # apk的launcherActivity
            'appActivity': 'com.aiosign.dzonesign.view.AppStartActivity',
        }
        self.logger.info('启动app')
        try:
            self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
            time.sleep(3)
            self.base_page = BasePage(self.driver)
            self.welcome_page = WelcomePage(self.base_page)
            self.login_page = LoginPage(self.base_page)
            self.main_page = MainPage(self.base_page)
        except Exception:
            BasePage.get_screen('screen_shot/')

    def teardown_method(self, method):
        print("断开连接")

    @allure.story('登录-用户不存在')
    def test_login_1(self):
        self.logger.info('开始测试test_login_1==================================')
        self.base_page.swipe_to_left()
        self.base_page.swipe_to_left()
        self.welcome_page.click_tiyan_button()
        self.welcome_page.click_login_button()
        self.login_page.input_username('15628811988')
        self.login_page.input_passwd('12345678')
        self.login_page.click_signin_button()
        res = self.base_page.is_toast_exist('用户不存在')
        assert res
        self.logger.info('测试结束=====================================')

    @allure.story('登录-账号或密码错误')
    def test_login_2(self):
        self.base_page.swipe_to_left()
        self.base_page.swipe_to_left()
        self.welcome_page.click_tiyan_button()
        self.welcome_page.click_login_button()
        self.login_page.input_username('123456')
        self.login_page.input_passwd('abc23')
        self.login_page.click_signin_button()
        res = self.base_page.is_toast_exist('账号或密码错误')
        assert res

    @allure.story('登录-正常')
    def test_right(self):
        self.logger.info('开始测试test_right=====================================')
        self.base_page.swipe_to_left()
        self.base_page.swipe_to_left()
        self.welcome_page.click_tiyan_button()
        self.welcome_page.click_login_button()
        self.login_page.input_username('123456')
        self.login_page.input_passwd('abcabc')
        self.login_page.click_signin_button()
        res = self.main_page.is_personal_center_button_exist()
        assert res
        # self.main_page.click_personal_center_button()
        # self.logger.info('测试完成')

    @allure.story('登录-未输入密码')
    def test_login_3(self):
        self.base_page.swipe_to_left()
        self.base_page.swipe_to_left()
        self.welcome_page.click_tiyan_button()
        self.welcome_page.click_login_button()
        self.login_page.input_username('123456')
        # self.login_page.input_passwd('')
        self.login_page.click_signin_button()
        res = self.base_page.is_toast_exist('请输入密码!')
        assert res

    @allure.story('登录-账号格式不正确')
    def test_login_4(self):
        self.base_page.swipe_to_left()
        self.base_page.swipe_to_left()
        self.welcome_page.click_tiyan_button()
        self.welcome_page.click_login_button()
        self.login_page.input_username('156288119')
        self.login_page.input_passwd('abcabc')
        self.login_page.click_signin_button()
        res = self.base_page.is_toast_exist('账号格式不正确(邮箱、信用代码、手机)')
        assert res

    @allure.story('登录-未输入账号')
    def test_login_5(self):
        self.base_page.swipe_to_left()
        self.base_page.swipe_to_left()
        self.welcome_page.click_tiyan_button()
        self.welcome_page.click_login_button()
        # self.login_page.input_username('')
        self.login_page.input_passwd('abcabc')
        self.login_page.click_signin_button()
        res = self.base_page.is_toast_exist('请输入账号!')
        assert res


if __name__ == '__main__':
    pytest.main(["--reruns", "3", "--reruns-delay", "2", "--alluredir", "result"])

运行此文件,控制台输出执行情况,如下:
别忘了启动appium和模拟器哦,在模拟器里预先安装好待测试的apk
在这里插入图片描述
其中.是测试通过的,R是重试的,F是失败的,E是出现异常的

4.4 生成个报告

在cmd中执行如下命令,生成测试报告:

allure generate result -o report --clean

在这里插入图片描述
接下来,我们需要去vscode中找到report目录下的index.html,用live server打开
[python]appium+pytest+allure移动端自动化(二)框架篇_第7张图片
pycharm中右键,用浏览器打开即可
直接在文件夹中双击index.html在浏览器中打开不行哦
报告如下:
[python]appium+pytest+allure移动端自动化(二)框架篇_第8张图片
可以点击各个具体的菜单,查看具体信息。

至此,一个大的架子基本搭建完成了。

你可能感兴趣的:(自动化测试,python)