App自动化

Appium 基础

安装 APK并打开

import time
from appium.webdriver import Remote

# apk 的路径
file = r'apk路径'
caps = {"platformName": "Android",
        "deviceName": "设备号",  # 可通过 adb devices 或者 adb get-serialno 获取
        "app": file}
driver=Remote(command_executor='http://127.0.0.1:4723/wd/hub',desired_capabilities=caps)  # 4723要与Appium客户端的端口号对应,4723为默认值
time.sleep(3)
driver.quit()

启动 APK

'''
获取apk包名
adb shell dumpsys activity activities | find "mFocusedActivity"
aapt dumpsys badging 电脑端apk路径  通过应用查看包名(配置aapt环境变量,或在aapt.exe路径下运行)
adb logcat | findStr -i displayed
adb shell pm list package -s  查询系统apk包名
adb shell pm list package -3  查询第三方apk包名
adb shell am monitor  查看将要启动或退出app的包名
adb shell dumpsys window windows | findstr mFocusedApp  查看当前界面的app的包名
adb shell dumpsys activity top | find "ACTIVITY"  查看启动的app的包名
adb shell dumpsys activity activities | findstr "Run"  查看所有启动的应用的包名
adb shell dumpsys window w |findstr \/ |findstr name=  查看当前启动应用的包名
'''
import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".guide.SplashActivity",
        "noReset": True}  # 清除应用缓存数据,比如避免app进行初始化操作
driver = Remote(command_executor='http://127.0.0.1:4723/wd/hub', desired_capabilities=caps)
size = driver.get_window_size()  # 获取屏幕像素 {'width': 2160, 'height': 3840}
time.sleep(2)
driver.quit()

查找元素

import time
from appium.webdriver import Remote

caps = {
    "platformName": "Android",
    "deviceName": "设备名",
    "appPackage": "包名",
    "appActivity": ".guide.SplashActivity",
    "noReset": True,
    # "unicodeKeyboard": True,  # 启用Unicode输入法,设置为true可以输入中文字符,默认为false
    # "resetKeyboard": True
}
driver = Remote(command_executor='http://127.0.0.1:4723/wd/hub', desired_capabilities=caps)

# 隐性等待
driver.implicitly_wait(10)

# 找元素
# xpath定位://class[@属性="值"]
xpath = "//android.widget.ImageView[@resource-id='com.qiduo.mail:id/titlebar_right_btn' and @index='1']"
el = driver.find_element("xpath", xpath)
# el = driver.find_element("class name","android.widget.ImageView")
print(el)
print(el.text)  # 打印文本
print(el.location)  # 获取元素在屏幕上的坐标
print(el.rect)  # 获取元素在屏幕上的坐标及长宽
print(el.get_attribute('class'))  # 获取元素的某属性的值
el.click()

driver.find_element("id", "com.qiduo.mail:id/email_addr_input").send_keys("哈哈")  # 输入
driver.find_element("id", "com.qiduo.mail:id/receive_server_login_name_input").clear()  # 清空文本框数据

checked_el = driver.find_element("id", "com.qiduo.mail:id/receive_server_encryption_checkbox")
if checked_el.get_attribute("checked") == "true":
    checked_el.click()

"""
定位方式:
通过 id 定位 resource-id 的值
通过 class name 定位 class 的值
通过 accessibility id 定位 content-desc 的值
"""
# 获取元素 text 属性值
print(driver.find_element("id", "com.qiduo.mail:id/receive_server_addr_label").text)
print(driver.find_element("id", "com.qiduo.mail:id/receive_server_addr_label").get_attribute("text"))

# 获取 content-desc 属性,如果 content-desc 属性为空,那么获取的就是 text 属性
print(driver.find_element("id", "com.qiduo.mail:id/receive_server_addr_label").get_attribute("name"))

# 获取元素 class 属性值
print(driver.find_element("id", "com.qiduo.mail:id/receive_server_addr_label").get_attribute("class"))
print(driver.find_element("id", "com.qiduo.mail:id/receive_server_addr_label").get_attribute("className"))

# 获取元素 id 属性值
print(driver.find_element("id", "com.qiduo.mail:id/receive_server_addr_label").get_attribute("resourceId"))

time.sleep(3)
driver.quit()

输入中文,目前不加下面两个参数也是可以添加中文的

caps["unicodeKeyboard"] = True
caps["resetKeyboard"] = True

显性等待

import time
from appium.webdriver import Remote
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity.MainActivity",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)

xpath = '//android.widget.ImageView[@resource-id="com.qiduo.mail:id/titlebar_toggle_slidingmenu_btn"]'

# 显性等待
locator = ("xpath", xpath)
wait = WebDriverWait(driver, timeout=8)
wait.until(expected_conditions.presence_of_element_located(locator))

el = driver.find_element("xpath", xpath)
print(el.text)
print(el.rect)

el.click()
time.sleep(3)
driver.quit()

打开 APP 指定到的活动页面

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity2.MainActivity",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
# driver.start_activity("包名", "活动页面名称")
driver.start_activity("包名", ".activity2.LoginActivity")  # 打开app指定到的活动页面

# send_keys
driver.find_element("id","定位元素1").send_keys("123456")  # 账号
driver.find_element("id","定位元素2").send_keys("abcdef")  #密码
driver.find_element("id","定位元素3").click()  # 登录

time.sleep(3)
driver.quit()

后台执行

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity2.MainActivity",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
time.sleep(1)
driver.background_app(5)  # 放到后台执行 driver.background_app(后台执行时间)
time.sleep(3)
driver.activate_app("com.android.settings")  # 激活app,将app放到前台执行
time.sleep(3)
driver.quit()

等待activity出现

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "127.0.0.1:62001",
        "appPackage": "包名",
        "appActivity": "引导页名称",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
driver.find_element("id", "com.lemon.lemonban:id/navigation_tiku").click()
print(driver.current_activity)  # 获取当前界面的activity
driver.wait_activity("等待的引导页名称", 5)
driver.find_element("xpath", "//android.widget.TextView[@text='text文本值']").click()
driver.wait_activity("等待的引导页名称", 5)
assert driver.find_element("xpath", "//android.widget.TextView[@text='text文本值']").get_attribute("text") == "text文本值"
time.sleep(3)
driver.quit()

滑动

滑动方法名称 实现方式 是否有惯性
swipe 传入坐标滑动 有惯性(当持续时间足够长时,实现的效果和drag_and_drop一致)
scroll 传入元素滑动 有惯性
drag_and_drop 传入元素滑动 无惯性

swipe滑动

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity2.MainActivity"}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
time.sleep(2)
# 获取屏幕尺寸
size = driver.get_window_size()
print(size)
width = size["width"]
height = size["height"]

# 从右往左滑动 driver.swipe(起始点x坐标, 起始点y坐标, 结束点x坐标, 结束点y坐标, 滑动的时间间隔(可以省略))
driver.swipe(width * 0.9, height * 0.5, width * 0.1, height * 0.5, 1000)
driver.implicitly_wait(10)

driver.find_element("id", "定位元素1").click()
driver.find_element("id", "定位元素2").click()
time.sleep(3)
driver.quit()

scroll滑动

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "com.android.settings",
        "appActivity": ".Settings",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
time.sleep(1)
origin_el = driver.find_element("xpath", "//android.widget.TextView[@text='电池']")
destination_el = driver.find_element("xpath", "//android.widget.TextView[@text='蓝牙']")
driver.scroll(origin_el, destination_el, 1000)  # 从电池的位置滑到蓝牙的位置
time.sleep(3)
driver.quit()

drag_and_drop滑动

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "emulator-5554",
        "appPackage": "com.android.settings",
        "appActivity": ".Settings",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
time.sleep(1)
origin_el = driver.find_element("xpath", "//android.widget.TextView[@text='电池']")
destination_el = driver.find_element("xpath", "//android.widget.TextView[@text='蓝牙']")
driver.drag_and_drop(origin_el, destination_el)
time.sleep(3)
driver.quit()

按键操作

import time
from appium.webdriver import Remote


class Key(object):
    """对按键进行封装"""
    enter = 66
    home = 3
    volume_up = 24
    volume_down = 25


def press_enter(driver):
    """对 enter 键进行单独的封装"""
    driver.press_keycode(Key.enter)


def press_home(driver):
    """对 home 键进行单独的封装"""
    driver.press_keycode(Key.home)


caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity2.MainActivity",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)

# 音量+
time.sleep(3)
driver.press_keycode(Key.volume_up)  # 音量+键

time.sleep(2)
# 按下home进一步的封装
press_home(driver)

time.sleep(2)
driver.quit()

tap模拟手势点击

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": "activity名称",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
driver.wait_activity(".activity.MainActivity", 10)
driver.tap([(1000, 3775)], 500)  # 下下策(更换手机后屏幕分辨率也改变,坐标需要改变)  # 模拟手势点击,最多支持五个点
# driver.tap([(743, 3660), (1416, 3840)], 500)
driver.wait_activity(".activity.DifficultyLevelActivity", 5)
el = driver.find_element("xpath", "//android.widget.TextView[@text='软件']")
assert el.text == "软件"
time.sleep(3)
driver.quit()

tap多点触控(目前测试一直报错,不知道为什么)

# 不能执行perform(),不知道为啥
import time
from appium.webdriver import Remote
from appium.webdriver.common.multi_action import MultiAction
from appium.webdriver.common.touch_action import TouchAction

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": "activity名称",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
driver.wait_activity(".activity.MainActivity", 10)
el1 = driver.find_element("xpath", "//*[@text='报名']")
el2 = driver.find_element("xpath", "//*[@text='社区']")
action1 = TouchAction(driver).tap(el1)
action2 = TouchAction(driver).tap(el2)
MultiAction(driver).add(action1,action2).perform()  # 不知道为什么显示“找不到.perform()”
time.sleep(3)
driver.quit()

long_press长按

import time
from appium.webdriver import Remote
from appium.webdriver.common.touch_action import TouchAction

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity2.MainActivity",
        "noReset": True}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
driver.wait_activity(".activity2.MainActivity", 10)
el = driver.find_element("id","id元素值")
TouchAction(driver).long_press(el=el,duration=5000).perform()  # 长按5秒
driver.find_element("id","com.youdao.note:id/btn_cancel").click()
time.sleep(3)
driver.quit()

手机 toast 弹窗处理

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity2.MainActivity",
        "automationName": "UiAutomator2",  # 识别手机Toast加上这个键值对
        "noReset": True}

driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)
time.sleep(3)
driver.start_activity("包名", ".activity2.LoginActivity")

driver.find_element("id", "元素").click()  # 登录

# 定位 toast
toast = driver.find_element("xpath", "//android.widget.Toast")  # 固定语法
# toast = driver.find_element("xpath", "//*[contains(@text, '用户名和密码不能为空')]")  # 通过toast文本定位
print(toast.text)

time.sleep(3)
driver.quit()

webview 处理(H5页面)

  • class 中,存在android.webkit.WebView需要用 webview 来处理

  • 谷歌浏览器访问chrome://inspect确认手机 webview 版本,下载chromedriver.exe驱动

    Snipaste_2023-07-31_20-52-36

  • webview 中的元素可以通过 UC 开发者工具定位,在设置中选择本地 Devtools Inspector UI 资源,在'Home'中点击inspect即可查看

    Snipaste_2023-07-31_21-01-52

import time
from appium.webdriver import Remote

caps = {"platformName": "Android",
        "chromedriverExecutableDir": r"D:\code\appium_record",  # 驱动位置
        "deviceName": "设备号",
        "appPackage": "包名",
        "appActivity": ".activity.MainActivity"}
driver = Remote(command_executor="http://127.0.0.1:4723/wd/hub", desired_capabilities=caps)
driver.implicitly_wait(10)

# 点击 师资团队 进入web页面
driver.find_element("xpath", "//*[@text='text的文本信息']").click()
time.sleep(5)

# 打印所有的上下文
print(driver.contexts)

# 上下文切换
driver.switch_to.context(driver.contexts[-1])
# driver.switch_to.context('WEBVIEW的名称')

# 注意:有时候一个页面会包含多个标签
print(driver.window_handles)

# 点击查看全部
driver.find_element("xpath", "//*[@id='__impage-component-wrapper-1']/section/div[1]/div/span/span").click()

time.sleep(3)
driver.quit()

封装

Appium运行原理

  1. 自动化脚本向AppiumServer发送注册参数(URL,platformName, platformVersion,deviceName,appPackage,appActivity)
  2. AppiumServer将bootstrap.jar包放入手机端中
  3. 手机端用bootstrap启动手机端口(4723),并将端口返回给AppiumServer(相当于建立好了通信连接)
  4. 自动化脚本发送请求(操作或命令或动作)给AppiumServer
  5. AppiumServer将请求解析并发送给bootstrap
  6. bootstrap将请求解析发给UIAutomator
  7. UIAutomator执行相应的操作并将结果返回给bootstrap
  8. bootstrap将响应结果返回给AppiumServer
  9. AppiumServer将响应结果返回到脚本

结构

python + appium + log +openpyxl

PO模式

Snipaste_2023-08-15_21-51-55

conftest.py夹具

import pytest

from appium_record.appium_practice_v4.pages.homepage import HomePage
from appium_record.appium_practice_v4.pages.tiku_page import TikuPage
from appium_record.appium_practice_v4.pages.tiku_page import CollectPage
from appium_record.appium_practice_v4.pages.userpage import UserPage
from appium_record.appium_practice_v4.common.logging_processing import logger
from appium_record.appium_practice_v4.common.excel import read_excel
from appium_record.appium_practice_v4.setting.path import path

case_datas_success = read_excel(path(r"data/cases.xlsx"), "login_success")
print(case_datas_success)


@pytest.fixture()
def driver():
    caps = {"platformName": "Android",
            "deviceName": "设备名称",
            "appPackage": "包名",
            "appActivity": "活动页名称"}
    d = Remote(command_executor='http://127.0.0.1:4723/wd/hub', desired_capabilities=caps)
    logger.info("成功打开app")
    d.implicitly_wait(10)
    yield d
    time.sleep(5)
    d.quit()
    logger.info("退出app")


@pytest.fixture(params=case_datas_success)
def login_params(request):
    return request.param

@pytest.fixture()
def login(driver, login_params):
    """登录功能"""
    HomePage(driver).enter_user()
    UserPage(driver).login(login_params["mobile"], login_params["passwd"])


@pytest.fixture()
def user_page(driver):
    return UserPage(driver)


@pytest.fixture()
def tiku_page(driver):
    return TikuPage(driver)

@pytest.fixture()
def collect_page(driver):
    return CollectPage(driver)

@pytest.fixture()
def home_page(driver):
    return HomePage(driver)

run.py:自动化运行入口

import pytest
import time
# import traceback
from appium_record.appium_practice_v4.common.logging_processing import logger

time_cur = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())

try:
    logger.info("开始运行自动化")
    pytest.main(["-s", r"--html=report/report_" + time_cur + ".html", '--capture=sys', '--disable-warnings'])
    # pytest.main(["tests/test_collect.py","-s", r"--html=report/report_" + time_cur + ".html",'--capture=sys','--disable-warnings'])
    # pytest.main(["-s", r"--html=report/report_" + time_cur + ".html",'--capture=sys','--disable-warnings','--log-cli-level=INFO'])
    # pytest.main(["-s"])
except Exception as e:
    logger.info(e)
    # logger.info(traceback.print_exc())
# pytest.main(["-s"])

common文件夹

basepage.py:封装常见的操作

from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

from appium_record.appium_practice_v4.common.logging_processing import logger


class Key(object):
    enter = 66
    home = 3
    volume_up = 24
    volume_down = 25


class BasePage:
    def __init__(self, driver):
        self.driver = driver

    def get_element(self, locator):
        """找元素 ("id", "")"""
        return self.driver.find_element(*locator)

    def wait_element_clickable(self, locator, timeout=10):
        """等待某个元素可以被点击"""
        wait = WebDriverWait(self.driver, timeout=timeout)
        return wait.until(expected_conditions.element_to_be_clickable(locator))

    def wait_element_visible(self, locator, timeout=10):
        """等待某个元素可见"""
        wait = WebDriverWait(self.driver, timeout=timeout)
        return wait.until(expected_conditions.visibility_of_element_located(locator))

    def click(self, locator):
        """点击某个元素"""
        # el = self.wait_element_clickable(locator)
        el = self.get_element(locator)
        el.click()

    def send_keys(self, locator, keyword):
        # el = self.wait_element_visible(locator)
        el = self.get_element(locator)
        el.send_keys(keyword)

    def swipe_down(self):
        """从上到下的滑动"""
        size = self.driver.get_window_size()
        print(size)
        width = size["width"]
        height = size["height"]
        self.driver.swipe(start_x=width * 0.5, start_y=height * 0.1, end_x=width * 0.5, end_y=height * 0.9)

    def swipe_up(self):
        """从下到上的滑动"""
        size = self.driver.get_window_size()
        print(size)
        width = size["width"]
        height = size["height"]
        self.driver.swipe(start_x=width * 0.5, start_y=height * 0.9, end_x=width * 0.5, end_y=height * 0.1)

    def swipe_left(self):
        """从右到左的滑动"""
        size = self.driver.get_window_size()
        width = size["width"]
        height = size["height"]
        try:
            self.driver.swipe(start_x=width * 0.9, start_y=height * 0.5, end_x=width * 0.1, end_y=height * 0.5, duration=1000)
        except Exception as e:
            logger.info(e)

    def swipe_right(self):
        """从左到右的滑动"""
        size = self.driver.get_window_size()
        width = size["width"]
        height = size["height"]
        self.driver.swipe(start_x=width * 0.1, start_y=height * 0.5, end_x=width * 0.1, end_y=height * 0.9)

    def press_keycode(self, key):
        """self.press_keycode(Key.enter)"""
        self.driver.press_keycode(key)

    def press_enter(self):
        """按回车 self.press_enter()"""
        self.driver.press_keycode(Key.enter)

    def get_toast_text(self):
        """获取 toast 文本"""
        el = self.get_element(("xpath", "//android.widget.Toast"))
        return el.text

excel.py:读取excel表格

import openpyxl


def read_excel(excel_path, sheet_name):
    workbook = openpyxl.load_workbook(excel_path)
    sheet_name = workbook[sheet_name]
    items = list(sheet_name.values)
    title = items[0]
    new_items = [dict(zip(title, item)) for item in items[1:]]
    return new_items

logging_processing.py封装日志,包括日志在控制台和文件上的文件

import logging
import datetime
import os
from logging.handlers import RotatingFileHandler
from appium_record.appium_practice_v4.setting.path import path

if not os.path.exists(path("log")):
    os.mkdir(path("log"))
    print("创建log文件夹成功")

log_path = path("log")
data = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S_%p")


class Logging():
    def __init__(self):
        self.logger = logging.getLogger('日志处理')
        self.logger.setLevel(logging.INFO)
        self.log_formatter = logging.Formatter(
            fmt="%(asctime)s,%(msecs)03d - %(levelname)s - [%(filename)s] - %(funcName)s - [line: %(lineno)d] - %(message)s",
            datefmt="%Y-%m-%d %p %H:%M:%S")

    def __create_console_handler(self):
        # self.console_handler = logging.handlers.TimedRotatingFileHandler('all.log', when='midnight', interval=1, backupCount=7, atTime=datetime.time(0, 0, 0, 0))
        self.console_handler = logging.StreamHandler()  # 默认是sys.stderr
        self.console_handler.setLevel(logging.DEBUG)
        self.console_handler.setFormatter(self.log_formatter)
        return self.console_handler

    def __create_file_handler(self):
        self.file_handler = logging.FileHandler(log_path / 'logs.log', encoding="utf-8")
        # self.file_handler = RotatingFileHandler(filename=log_path / f"log_{data}.log", mode="a", maxBytes=5 * 1024 * 1024, backupCount=5, encoding='utf-8')
        self.file_handler.setLevel(logging.INFO)
        self.file_handler.setFormatter(self.log_formatter)
        return self.file_handler

    def add_handler(self):
        self.__create_console_handler()
        self.__create_file_handler()
        if not self.logger.handlers:
            self.logger.addHandler(self.console_handler)
            self.logger.addHandler(self.file_handler)
        return self.logger


logger = Logging().add_handler()

cases存放测试用例

image-20230815215840542

pages文件夹:存档坐标和页面的操作

from appium_record.appium_practice_v4.common.basepage import BasePage
from appium_record.appium_practice_v4.common.logging_processing import logger


class UserPage(BasePage):
    avator_locator = ("id", "元素")
    mobile_locator = ("id", "元素")
    password_locator = ("id", "元素")
    login_confirm_locator = ("id", "元素")
    # Toast 弹框
    toast_locator = ("xpath", "//android.widget.Toast")
    username_locator = ("id", "元素")
    tiku_locator = ("id", "元素")

    def login(self, mobile_phone, password):
        self.click(self.avator_locator)
        logger.info("点击头像登录")
        if mobile_phone:
            self.send_keys(self.mobile_locator, mobile_phone)
            logger.info(f"输入账号'{mobile_phone}'")
        if password:
            self.send_keys(self.password_locator, password)
            logger.info(f"输入密码'{password}'")
        self.click(self.login_confirm_locator)
        logger.info("点击'登录'")

    def get_error_msg(self):
        """获取登录失败的错误信息"""
        toast = self.get_element(self.toast_locator)
        logger.info(f"toast信息为'{toast.text}'")
        return toast.text

    def get_username(self):
        """获取用户昵称"""
        el = self.get_element(self.username_locator)
        logger.info(f"用户昵称为'{el.text}'")
        return el.text

    def enter_tiku(self):
        self.click(self.tiku_locator)

setting:存放配置信息

from pathlib import Path


def path(path):
    project_path = Path(__file__).absolute().parent.parent
    return project_path / path

tests文件夹:存放测试用例

import pytest
from pages.homepage import HomePage
from appium_record.appium_practice_v4.pages.userpage import UserPage
from appium_record.appium_practice_v4.common.logging_processing import logger
from appium_record.appium_practice_v4.common.excel import read_excel
from appium_record.appium_practice_v4.setting.path import path

"""
数据驱动测试(ddt) data driven testing.
多组数据, 测试逻辑,测试步骤
"""

# case_data = [dict(mobile_phone="123", password="456", expected="手机号码格式不正确"),
#              dict(mobile_phone="", password="", expected="手机号码或密码不能为空")]
case_datas = read_excel(path(r"data/cases.xlsx"),"login_fail")

# case_data_success = [dict(mobile_phone="正确的手机号", password="正确的密码", expected="期望值")]
case_datas_success = read_excel(path(r"data/cases.xlsx"),"login_success")


class TestLogin():
    @pytest.mark.parametrize("case_data", case_datas)
    def test_login(self, driver, case_data):
        HomePage(driver).enter_user()
        user_page = UserPage(driver)
        mobile_phone = case_data.get("mobile")
        password = case_data.get("passwd")
        expected = case_data.get("expected")
        # user_page.login(case_info["mobile_phone"], case_info["password"])
        user_page.login(mobile_phone, password)
        actual = user_page.get_error_msg()
        # assert actual == case_info["expected"]
        assert actual == expected
        logger.info("----------------PASS----------------")

    @pytest.mark.parametrize("case_info", case_datas_success)
    def test_login_success(self, driver, case_info):
        HomePage(driver).enter_user()
        mobile_phone = case_info.get("mobile")
        password = case_info.get("passwd")
        expected = case_info.get("expected")
        UserPage(driver).login(mobile_phone, password)
        actual = UserPage(driver).get_username()
        assert actual == expected
        logger.info("----------------PASS----------------")
posted @ 2023-08-14 22:24  暮雨星辰  阅读(121)  评论(0)    收藏  举报