addTests 的用法应该是这样的吧,suite.addTests([UserTestCase2("testCase3"), UserTestCase2("testCase1"), UserTestCase("testCase1")])
suite.addTests(DevOpsRoleCases) 这个看起来是加载了一个类?应该具体到这个类(DevOpsRoleCases)里面的用例吧?
想要全量执行某个类中的所有用例请用 unittest.defaultTestLoader.discover
还有一个问题是,如果集成到框架里,5037 端口也是 appium 所需要构建 session 连接的,这个图像识别完之后会导致 appium 的 driver 断开链接
我试了下,里面集成了 airtest 的图像识别。成功了一两次,可能还是图标太小了。不过方法还是很好的
图像识别不靠谱,还是老老实实的让开发加 id 吧 关闭的按钮太小了,识别不到
广告的样式很多种的,大小宽度都会变化,不是固定的坐标就行的,目前感觉 appium 不能操作的话只能靠图像识别返回坐标位置再去点击操作
问题来源: 当我们执行 UI 自动化测试时可能会涉及到,一台手机跑多个用例的过程亦或者多个 APP 的过程测试,但是一台手机只允许一个模块或者一个 APP 的自动化测试,因此 JOB 之间存在着手机资源的争抢问题,为了防止两个模块被同时进行(因为可能不是自己操作,自己操作会主动去看下,但是不清楚的业务测试同学我们需要帮他们去规避这个问题)
安装 Lockable Resources 插件,插件的主要功能
安装完毕后进行重启 Jenkins
根据自己需要给资源起个 Name 和标签即可,应用并保存
当 UI_Auto_Search 执行时,BBJ_Auto_Search 被放在构建队列中,此时资源不足,需要等待构建,我们也可以主动去释放资源,释放完,可以正常构建。
目前是不需要一个 job 执行完去执行另一个,只是为了防止有时两个 job 被不同的人都在执行同一台手机,导致打架
谢谢提供建议,很中肯。第二点感觉可以满足需求
http://testerhome.com/topics/32639 可以看下这篇帖子内容
好的,我发在楼下了
from concurrent.futures.process import ProcessPoolExecutor
import os
import time
import pytest
import yaml
from meet.public import *
from meet.concurrent_startup import *
devices_list = ['Your device uid', 'Your device uid']
def runnerPool():
with open('kyb_caps.yaml', 'r', encoding="utf-8")as file:
data = yaml.load(file, Loader=yaml.FullLoader)
print(data)
devices_Pool = data
with ProcessPoolExecutor(len(devices_Pool)) as pool:
pool.map(runPytest, devices_Pool)
def runPytest(device):
print(f"cmdopt is {device}")
report = f"report-{device['deviceName']}".split(":", 1)[0]
report_dir = mkdir_dir(report)
now_time = time.strftime("%H-%M-%S", time.localtime())
print(f"pool run device is {device['deviceName']}")
pytest.main(["-s", "./TestCases/", f"--cmdopt={device}", "--alluredir", f"./{report_dir}/{now_time}/xml"])
time.sleep(1)
os.system(f"allure generate ./{report_dir}/{now_time}/xml -o ./{report_dir}/{now_time}/html")
if __name__ == '__main__':
"""
获取服务的端口
并发启动appium的服务
多设备启动执行用例
release端口
"""
ports = []
appium_start_sync()
runnerPool()
for i in range(len(devices_list)):
port_num = 4723 + 2 * i
ports.append(port_num)
print(ports)
for t in ports:
release_port(t)
import time
def mkdir(path):
"""创建目录函数"""
import os
path = path.strip() # 去除首位空格
path = path.rstrip("\\") # 去除尾部 \ 符号
is_exists = os.path.exists(path) # 判断路径是否存在
if not is_exists:
os.makedirs(path) # 不存在目录则创建
print(path + "创建成功")
return True
else:
print(path + "目录已存在") # 如果目录存在则不创建,并提示目录已存在
return False
def mkdir_dir(path):
"""创建当天相应的目录"""
now_date = time.strftime("%Y-%m-%d", time.localtime())
main_path = f"{path}"
global dir_path
dir_path = (main_path + '/' + now_date)
mkdir(dir_path)
return dir_path
def get_failed_screenshot(self, current_case_name):
"""获取失败截图函数"""
now_date = time.strftime("%Y-%m-%d", time.localtime())
now_time = time.strftime("%Y-%m-%d %H-%M-%S", time.localtime())
global dir_path
self.driver.get_screenshot_as_file(dir_path + "/" + now_time + " " + current_case_name + ".png")
import pytest
from appium import webdriver
def pytest_addoption(parser):
parser.addoption("--cmdopt", action="store", default="device", help="None")
@pytest.fixture(scope="session")
def cmdopt(request):
return request.config.getoption("--cmdopt")
@pytest.fixture
def connectDevice(cmdopt):
device = eval(cmdopt)
device_caps = {}
device_caps["platformVersion"] = device["platformVersion"]
device_caps["platformName"] = device['platformName']
device_caps["deviceName"] = device['deviceName']
device_caps["udid"] = device['udid']
device_caps["appPackage"] = device['appPackage']
device_caps["appActivity"] = device['appActivity']
device_caps["newCommandTimeout"] = device["newCommandTimeout"]
device_caps["noReset"] = True
device_caps["noSign"] = True
device_caps["unicodeKeyboard"] = True
device_caps["resetKeyboard"] = True
device_caps["systemPort"] = device["systemPort"]
remote = "http://127.0.0.1:" + str(device["port"]) + "/wd/hub"
driver = webdriver.Remote(remote, device_caps)
yield driver
driver.close_app()
driver.quit()
# coding=utf-8
import subprocess
import socket
from time import ctime
import multiprocessing
import os
from meet.public import *
def check_port(host, port):
"""
检测指定的端口是否被占用
:param host:
:param port:
:return:
"""
# 创建socket对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host, port))
s.shutdown(2)
except OSError as msg:
print('----------port %s is available! ----------' % port)
print(msg)
return True
else:
print('----------port %s already be in use !-----------' % port)
return False
def release_port(port):
"""
释放指定的端口
:param port:
:return:
"""
# 查找对应端口的pid
cmd_find = 'netstat -aon | findstr %s' % port
print(cmd_find)
# 返回命令执行后的结果
result = os.popen(cmd_find).read()
print(result)
if str(port) and 'LISTENING' in result:
# 获取端口对应的pid进程
i = result.index('LISTENING')
start = i + len('LISTENING') + 7
end = result.index('\n')
pid = result[start:end]
# 关闭被占用端口的pid
cmd_kill = 'taskkill -f -pid %s' % pid
print(cmd_kill)
os.popen(cmd_kill)
else:
print('----------port %s is available !-----------' % port)
def appium_start(host, port):
"""
启动appium服务
:param host:
:param port:
:return:
"""
bootstrap_port = str(port + 1)
# cmd = 'start /b appium -a ' + host + ' -p ' + str(port) + ' --bootstrap-port ' + str(bootstrap_port) # linux下
cmd = 'start node G:\\Appium\\resources\\app\\node_modules\\appium\\build\lib\\main.js -a ' + host + ' -p ' + str(
port) + ' --bootstrap-port ' + str(bootstrap_port) # win调试
print('%s at %s' % (cmd, ctime()))
mkdir("appium_log")
subprocess.Popen(cmd, shell=True, stdout=open('./appium_log/' + str(port) + '.log', 'a'), stderr=subprocess.STDOUT)
def start_appium_action(host, port):
"""
检测端口是否被占用,如果没有被占用则启动appium服务
:param host:
:param port:
:return:
"""
if check_port(host, port):
appium_start(host, port)
return True
else:
print("----------appium %s already start!----------" % port)
return True
def appium_start_sync(devices_list):
"""
并发启动appium服务
:return:
"""
appium_process = []
# 加载appium进程
for i in range(len(devices_list)):
host = '127.0.0.1'
port = 4723 + 2 * i
appium = multiprocessing.Process(target=start_appium_action, args=(host, port))
appium_process.append(appium)
# 启动appium服务
for appium in appium_process:
appium.start()
for appium in appium_process:
appium.join()
import allure
from selenium.webdriver.support.wait import WebDriverWait
from unittest import TestCase
import pytest
import time
from appium import webdriver
class TestMyConcurrent(object):
@allure.feature("group_Call")
@allure.story("search_Case")
def test_001(self, connectDevice):
"""
测试用例一
connectDevice = driver
:param connectDevice:
:return:
"""
time.sleep(5)
connectDevice.find_element_by_id("yiyayiyayo").click()
time.sleep(2)
print("已点击咿呀咿呀哟")
time.sleep(5)
@allure.feature("group_Call")
@allure.story("search_Case")
def test_002(self, connectDevice):
"""
测试用例二
:return:
"""
time.sleep(5)
connectDevice.find_element_by_id("sousuokuang").click()
time.sleep(2)
connectDevice.find_element_by_id("sousuokuang").send_keys("天气")
time.sleep(2)
connectDevice.find_element_by_id("sousuo_btn").click() # 点击搜索
print("已完成点击搜索")
time.sleep(5)
connectDevice.keyevent(4)
time.sleep(2)
connectDevice.keyevent(4)
print("已返回主页")
@allure.feature("group_Call")
@allure.story("search_Case")
def test003(self, connectDevice):
"""测试用例三"""
while True:
try:
connectDevice.find_element_by_xpath("//*[contains(@text,'更多')]").click()
break
except:
time.sleep(5)
print("点击完成更多")
time.sleep(5)
connectDevice.keyevent(4)
print("从更多页面返回主页")
time.sleep(4)
- platformName: Android
platformVersion: "10"
deviceName: 123456gf
appPackage: package_name
appActivity: package_home_name
udid: 123456gf
systemPort: 8208
newCommandTimeout: 6000
port: 4723
- platformName: Android
platformVersion: "11"
deviceName: sdakla9312
appPackage: package_name
appActivity: package_home_name
udid: sdakla9312
systemPort: 8209
newCommandTimeout: 6000
port: 4725
adb shell dumpsys window | findstr mCurrentFocus 荣耀手机 鸿蒙 2.0 可用 一般我都是用这个命令
没怎么玩桌面自动化,http://www.kikicyo.com/article/27/ 之前看到有个 WinAppDriver,写了个 demo,不知道适不适用你这个
感谢各位大神
我想应该是这样的,td[1] 可能是 p 标签下的 td1,可能是 div 标签下的 td1,那这样系统就把所有标签下有 td1 的都拿出来了,因为你前面没有加其他的条件,比如//div[@id='title']/td[1]。
shake() 方法未实现,目前没有看到能执行相关功能的命令或方法
有心了,放收藏夹吃灰了
国外对单元测试很看重,国内嘛 emmm
弹出一个"javascript:;" 是长啥样的,可以尝试使用 get_cookies() 和 add_cookie(cookie_dict) 的方式看下能不能绕过登录页面
引发这个报错的原因可能是,在刚要点击这个元素时,有一层新的元素刷新了 dom 树,导致要点击的元素上面覆盖了一层弹框,selenium 应该不会提供这种现成的方法,如果很多地方会遇到这个问题,可以自己封装一个方法,并且把执行方式可以换成:
element = driver.find_element_by_css('div[class*="loadingWhiteBox"]')
driver.execute_script("arguments[0].click();", element)
看了下自己博客之前竟然也遇到过这种问题,你可以试看看
https://blog.csdn.net/Python_BT/article/details/108365605?spm=1001.2014.3001.5501
这不是很好解决么,捕获异常等个几秒去重试点击就好了啊
换个定位方法?XPATH 的用, (//*[@text='确定'])