PPT
代码地址
课后调查表
https://jinshuju.net/f/Xdpzjw
连接设备
mac: adb kill-server&&adbdevices
window:adb connect 127.0.0.1:7555
获取包名和页面名
mac/linux : adb logcat ActivityManager:I | grep "cmp"
windows: adb logcat ActivityManager:I | findstr "cmp"
- 第一步:先在手机上关闭应用程序(被测应用程序)
- 第二步:执行上面的命令
- 第三步:启动被测应用程序
添加成员
"""
__author__ = '霍格沃兹测试开发学社'
__desc__ = '更多测试开发技术探讨,请访问:https://ceshiren.com/t/topic/15860'
"""
# This sample code uses the Appium python client
# pip install Appium-Python-Client
# Then you can paste this into a file and simply run with Python
# pip install appium-python-client
from time import sleep
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from faker import Faker
from selenium.common import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait
class TestContact:
_IMPLICITLY = 20
def setup_class(self):
self.faker = Faker('zh_CN')
def setup(self):
# 准备工作
# 字典对象 desirecapbility
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "emulator-5554"
caps["appPackage"] = "com.tencent.wework"
caps["appActivity"] = ".launch.LaunchSplashActivity"
# 防止 每次启动都关闭app 再重新启动,这个参数要与noReset 结合使用才会生效
caps["dontStopAppOnReset"] = "true"
# 设置运行过一次之后,就可以跳过服务的安装,跳过设备的初始化,提升启动速度
caps["skipDeviceInitialization"] = "true"
caps["skipServerInstallation"] = "true"
caps["noReset"] = "true"
# 最重要的步骤!! 让我们的客户端与appium server 服务端建立 连接最关键的一步
# 服务端会返回一个session对象,存放了要测试的设备信息
# 与server 建立连接的时候 ,默认打开 desirecaps里配置的启动页面
self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
self.driver.implicitly_wait(self._IMPLICITLY)
def set_implicit(self,waittime):
self.driver.implicitly_wait(waittime)
def swipe_find(self, text, max_num = 3):
"""滑动查找"""
# max_num = 3
self.set_implicit(1)
for i in range(max_num):
try:
# 每次找元素都要等足 _IMPLICITLY 隐式等待时长
element = self.driver.find_element(AppiumBy.XPATH, f"//*[@text='{text}']")
self.set_implicit(self._IMPLICITLY)
return element
except NoSuchElementException:
# 滑动
size = self.driver.get_window_size()
# 'width', 'height'
startx = size.get("width")/2
starty = size.get("height") * 0.8
endx = startx
endy = size.get("height") * 0.3
duration = 500
self.driver.swipe(startx,starty,endx,endy,duration)
if i == max_num-1:
# 找了最大次数 ,仍然未找到
self.set_implicit(self._IMPLICITLY)
raise NoSuchElementException(f"找了 {max_num} 次,未找到 {text}")
def test_addcontact(self):
"""
添加联系人
"""
name = self.faker.name()
phonenumber = self.faker.phone_number()
# 进入【通讯录】页面
self.driver.find_element(AppiumBy.XPATH, "//*[@text='通讯录']").click()
# 点击【添加成员】
# self.driver.find_element(AppiumBy.XPATH, "//*[@text='添加成员']").click()
self.swipe_find("添加成员", 3).click()
# 点击【手动输入添加】
self.driver.find_element(AppiumBy.XPATH, "//*[@text='手动输入添加']").click()
# 输入【姓名】【手机号】并点击【保存】
# 找到第一次出现的元素 就返回
# self.driver.find_element(AppiumBy.XPATH, "//*[@text='必填']").send_keys(name)
self.driver.find_element(AppiumBy.XPATH, "//*[contains(@text,'姓名')]/../*[@text='必填']").send_keys(name)
# 第一种方式通过 查找它们公共的父结点->找子孙结点里的EditText
self.driver.find_element(AppiumBy.XPATH, "//*[contains(@text,'手机')]/..//android.widget.EditText").send_keys(
phonenumber)
# 第二种:通过查找公共的父结点->找子孙结点里文字为[必填]的元素
# //*[contains(@text,'手机')]/..//*[@text='必填']
self.driver.find_element(AppiumBy.XPATH, "//*[@text='保存']").click()
# 验证点:登录成功提示信息
# sleep(2)
# print(self.driver.page_source)
# 等待 toast 出现, 默认使用隐式等待,
toast = self.driver.find_element(AppiumBy.XPATH, "//*[@class='android.widget.Toast']").text
assert "添加成功" == toast
# 纯显式等待查找
# WebDriverWait(self.driver, 10).until(lambda x:"添加成员" in x.page_source)
# 显式等待+隐式等待
# WebDriverWait(self.driver,10).until(lambda x:x.find_element(AppiumBy.XPATH,"//*[@class='android.widget.Toast']"))
def teardown(self):
# 资源回收
self.driver.quit()
作业
- 前提条件:
- 1、提前注册企业微信管理员帐号
- 2、手机端安装企业微信
- 3、企业微信 app 处于登录状态
- 实现打卡功能
- 打开【企业微信】应用
- 进入【工作台】页面
- 点击【打卡】
- 选择【外出打卡】tab
- 点击【第 N 次打卡】
- 验证点:提示【外出打卡成功】
# author: 一路向北
# project:pythonProject
# name: test_clock_in.py
# date: 2022/8/14
"""
实现打卡功能
打开【企业微信】应用
进入【工作台】页面
点击【打卡】
选择【外出打卡】tab
点击【第 N 次打卡】
验证点:提示【外出打卡成功】
"""
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
class TestClockIn:
# 隐式等待时长
__IMPLICITLY = 5
def implicitly_set(self, wait_time):
self.driver.implicitly_wait(wait_time)
def find_click(self, by, locator):
# 正常查找并点击
# self.driver.find_element(by,locator).click()
# 加上显示等待,等元素可以点击后再点击
WebDriverWait(self.driver, 5).until(expected_conditions.element_to_be_clickable((by, locator))).click()
def swipe_find(self):
self.implicitly_set(1)
# 最大查找次数
max_try_num = 3
for i in range(max_try_num):
# 尝试定位目标元素
try:
element = self.driver.find_element(MobileBy.XPATH, "//*[@text='打卡']")
self.implicitly_set(self.__IMPLICITLY)
return element
# 未找到目标元素,滑动页面
except NoSuchElementException:
# 将【工作台】页面往下滑动,以便可以看到【打卡】选项
window_size = self.driver.get_window_size()
x1 = window_size['width'] / 2
y_start = window_size['height'] * 4 / 5
y_end = window_size['height'] * 1 / 5
duration = 500
self.driver.swipe(x1, y_start, x1, y_end, duration)
# 找了最大次数后仍未找到,抛出异常
if i == max_try_num - 1:
self.implicitly_set(self.__IMPLICITLY)
raise NoSuchElementException(f"滑动了{max_try_num}次,仍未找到目标元素")
def setup(self):
# 准备工作
# 打开【企业微信】应用
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "emulator-5554"
caps["appPackage"] = "com.tencent.wework"
caps["appActivity"] = ".launch.LaunchSplashActivity"
# 防止 每次启动都关闭app 再重新启动,这个参数要与noReset 结合使用才会生效
caps["dontStopAppOnReset"] = "true"
caps["noReset"] = "true"
# 与server 建立连接的时候 ,默认打开 desirecaps里配置的启动页面
self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
self.implicitly_set(self.__IMPLICITLY)
def test_clock_in(self):
"""
添加联系人
"""
# 进入【工作台】页面
self.find_click(MobileBy.XPATH, "//*[@text='工作台']")
# 点击【打卡】
self.swipe_find().click()
# 选择【外出打卡】tab
self.find_click(MobileBy.ID, "com.tencent.wework:id/jt8")
# 点击【第 N 次打卡】
self.find_click(MobileBy.XPATH, "//*[contains(@text,'次外出')]")
# 验证点:提示【外出打卡成功】
toast = self.driver.find_element(MobileBy.ID, "com.tencent.wework:id/rr").text
assert "外出打卡成功" == toast
def teardown(self):
# 资源回收
self.driver.quit()
NickGuo
(郭亚豪)
4
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from faker import Faker
from selenium.common import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait
class TestAppiumWework:
_IMPLICITLY = 8
def setup(self):
cap = {}
cap["platformName"] = "Android"
cap["appPackage"] = "com.tencent.wework"
cap["appActivity"] = ".launch.LaunchSplashActivity"
cap["deviceName"] = "WeworkDevice"
# 设置动态页面的等待时长
cap['settings[waitForIdleTimeout]'] = 0
cap["noReset"] = True
# 防止 每次启动都关闭app 再重新启动,这个参数要与noReset 结合使用才会生效
cap["dontStopAppOnReset"] = True
# 设置运行过一次之后,就可以跳过服务的安装,跳过设备的初始化,提升启动速度
cap["skipDeviceInitialization"] = True
cap["skipServerInstallation"] = True
self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", cap)
self.set_implicitly(self._IMPLICITLY)
def teardown(self):
self.driver.quit()
def set_implicitly(self, waittime):
self.driver.implicitly_wait(waittime)
def test_addcontent(self):
'''
添加联系人
:return:
'''
# 进入[通讯录]页面
self.driver.find_element(AppiumBy.XPATH, "//*[@text='通讯录']").click()
# 点击[添加成员]
self.swipe_find("添加成员").click()
# 点击[手动输入添加]
self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[contains(@text, '手动输入添加')]").click()
# 输入[姓名][手机号]并点击[保存]
faker1 = Faker("zh_Cn")
username = faker1.name()
mobile = faker1.phone_number()
self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[contains(@text, '姓名')]"
"/following-sibling::android.widget.EditText[1]").send_keys(username)
self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[contains(@text, '手机')]//"
"following-sibling::android.widget.RelativeLayout[1]//"
"android.widget.RelativeLayout//"
"android.widget.EditText[@text='必填']").send_keys(mobile)
# "//android.widget.TextView[contains(@text, '手机')]/..//android.widget.EditText[contains(@text, '必填')]"
self.driver.find_element(AppiumBy.XPATH, "//*[@text='保存']").click()
# sleep(2)
# print(self.driver.page_source)
# 找到第一次出现的元素就返回
# 第一种方式通过查找他们公共的父节点-->找子孙节点的EditText
# 第二种:通过查找公共的父结点->找子孙结点里文字为[必填]的元素
# 验证点:登录成功提示信息
# 等待 toast 出现, 默认使用隐式等待,调用find_element会触发隐式等待
toast = self.driver.find_element(AppiumBy.XPATH, "//*[@class='android.widget.Toast']").text
# 纯显示等待
# WebDriverWait(self.driver, 10).until(lambda x: "添加成员" in x.page_source)
# 显示等待+隐式等待
# WebDriverWait(self.driver, 10).until(lambda x: x.find_element(AppiumBy.XPATH, "android.widget.Toast"))
assert "添加成功" == toast
# 纯显式等待查找
# 显式等待+隐式等待
def test_punch_out(self):
# 进入[工作台]页面
self.driver.find_element(AppiumBy.XPATH, "//*[@text='工作台']").click()
# 点击[打卡]
self.swipe_find("打卡").click()
self.driver.find_element(AppiumBy.XPATH, "//*[@text='完成']").click()
self.swipe_find("打卡").click()
# 选择[外出打卡]tab
self.driver.find_element(AppiumBy.XPATH, "//*[contains(@text, '外出打卡')]").click()
# 点击[第N次打卡]
self.driver.find_element(AppiumBy.XPATH, "//*[contains(@text, '次外出')]").click()
# self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, new UIScrollable scrollintoview)
result = self.driver.find_element(AppiumBy.XPATH, "//*[@text='外出打卡成功']").text
assert "外出打卡成功" == result
# 通过swipe向上滑动直到页面能看到"添加成员"按钮
def swipe_find(self, text):
size = self.driver.get_window_size()
width = size.get("width")
height = size.get("height")
start_x = width / 2
start_y = height * 0.8
end_x = width / 2
end_y = height * 0.3
duration = 500
# 循环查找"添加成员"按钮
nums = 4
self.set_implicitly(1)
for i in range(nums):
try:
ele = self.driver.find_element(AppiumBy.XPATH, f"//*[@text='{text}']")
self.set_implicitly(self._IMPLICITLY)
return ele
except NoSuchElementException:
self.driver.swipe(start_x, start_y, end_x, end_y, duration)
if i == nums - 1:
self.set_implicitly(self._IMPLICITLY)
raise NoSuchElementException(f"找了{nums}次,未找到{text}")
![01|800x249](upload://2DlHcfCmfG7TbSC6GHB0gP4syoc.png)
![02|516x1019](upload://8grg6sYk8qwhZd4wGczQkqlEcVI.png)
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from faker import Faker
from selenium.common.exceptions import NoSuchElementException
class TestWechat:
_IMPLICITLY = 20
def setup_class(self):
testfaker = Faker("zh_Cn")
self.name = testfaker.name()
self.phone = testfaker.phone_number()
def setup(self):
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '6.0'
desired_caps['deviceName'] = '127.0.0.1:7555'
desired_caps['appPackage'] = 'com.tencent.wework'
desired_caps['appActivity'] = '.launch.LaunchSplashActivity'
desired_caps['noReset'] = 'true'
# 设置动态页面等待时间
desired_caps['settings[waitForIdleTimeout]'] = 100
# 不重启应用
desired_caps['dontStopAppOnReset'] = 'true'
# 跳过安装服务
desired_caps['skipServerInstallation'] = True
# 跳过设备的初始化
desired_caps['skipDeviceInitialization'] = 'true'
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# 每次find_element的时候都会显示等待,一般来说,这种显示等待已经够了,所以不需要再去设置等待
self.driver.implicitly_wait(self._IMPLICITLY)
def teardown(self):
self.driver.quit()
# 切换等待时间方法,由于每次查找都会显示等待,所以滑动查找的时候,需要临时将等待时长缩短
def set_implicit(self, waittime):
self.driver.implicitly_wait(waittime)
def swipe_find(self,text,max_num = 3):
self.set_implicit(1)
for i in range(max_num):
try:
element = self.driver.find_element(MobileBy.XPATH,f"//*[@text='{text}']")
self.set_implicit(self._IMPLICITLY)
return element
except NoSuchElementException:
# 获取当前手机尺寸
size = self.driver.get_window_size()
startx = size.get("width")/2
starty = size.get("height")*0.8
endx = startx
endy = size.get("height")*0.3
# swipe滑动操作,duration滑动时间
self.driver.swipe(startx,starty,endx,endy,duration=500)
if i == max_num-1:
# 如果超过查找最大次数,抛出异常
self.set_implicit(self._IMPLICITLY)
raise NoSuchElementException(f"找了{max_num}次,没找到")
def test_case(self):
self.driver.find_element(MobileBy.XPATH,"//*[@text='通讯录']").click()
# self.driver.find_element(MobileBy.XPATH,"//*[@text='添加成员']").click()
self.swipe_find('添加成员').click()
self.driver.find_element(MobileBy.XPATH,"//*[@text='手动输入添加']").click()
# 由于可能text中包含空格,所以可以通过contains去定位包含某些文本的元素
self.driver.find_element(MobileBy.XPATH,"//*[contains(@text,'姓名')]/../*[@text='必填']").send_keys(self.name)
self.driver.find_element(MobileBy.XPATH,"//*[contains(@text,'手机')]/..//*[@text='必填']").send_keys(self.phone)
self.driver.find_element(MobileBy.XPATH,"//*[@text='保存']").click()
# time.sleep(4)
# print(self.driver.page_source)
toast = self.driver.find_element(MobileBy.XPATH, "//*[@class='android.widget.Toast']").text
assert "添加成功" == toast
def test_clock(self):
self.driver.find_element(MobileBy.XPATH,"//*[@text='工作台']").click()
self.swipe_find('打卡').click()
self.driver.find_element(MobileBy.ID,"com.tencent.wework:id/jt8").click()
n = self.driver.find_element(MobileBy.ID,"com.tencent.wework:id/bdt").text
self.driver.find_element(MobileBy.XPATH,f"//*[@text='{n}']").click()
result = self.driver.find_element(MobileBy.ID,"com.tencent.wework:id/rr").text
# time.sleep(4)
# print(self.driver.page_source)
assert "外出打卡成功" == result