之前在做手机app 自动化的时候,每次在自动化测试脚本运行之前,需要手动启动appium 服务器,
在开发环境中这样做没有什么问题,但是在服务器端执行自动化代码,这样就有有欠妥当。
python代码通过 python的方式启动 appium 服务。
python执行命令行命令
os.system 执行命令
import os
os.system('ping www.baidu.com')
os.system 方法可以模拟执行命令行命令。但是缺点是:它是同步的,当命令行中的命令执行完成之后,才会接着往下执行。
subprocess 子进程的方式执行
以后台服务的方式启动appium
# 启动状态 -- 后台启动
with open('./data.log',mode='w',encoding='utf-8') as f:
subprocess.Popen("appium",shell=True,stdout=f)
关闭appium 进程
Windows操作系统 使用netstat 命令来根据端口号找到对应 进程号,再根据进程号使用命令结束即可
查看进程号
Windows命令
netstat -ano | findstr 4723
根据找到的进程号结束进程
taskkill -f -pid 19760
mac系统的命令
mac 查看端口占用进程
lsof -i tcp:4723
杀掉进程
kill pid
更改conftest.py 文件,自动启动appium 以及 自动关闭appium
from appium import webdriver
import pytest
import os,sys,subprocess
from appium.webdriver.webdriver import WebDriver
chromedriver= os.path.join(os.path.dirname(os.path.abspath(__file__)),'drivers/chromedriver.exe')
def stop_appium(port):
"""
停止appium
:param port: 启动的端口号
:return:
"""
mac_cmd = f"lsof -i tcp:{port}"
win_cmd = f"netstat -ano | findstr {port}"
# 判断操作系统
os_platform = sys.platform
if os_platform == "win32": #windows 系统
win_p = subprocess.Popen(win_cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
for line in win_p.stdout.readlines():
if line:
line = line.decode('utf8')
if "LISTENING" in line:
win_pid = line.split("LISTENING")[1].strip()
os.system(f"taskkill -f -pid {win_pid}")
else: # unix系统
p = subprocess.Popen(mac_cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
for line in p.stdout.readlines():
line = line.decode('utf8')
# print("line",line)
if "node" in line:
stdoutline = line.split(" ")
print(stdoutline)
pid = stdoutline[4]
os.system(f"kill {pid}")
def start_appium(port):
"""
启动appium 服务
:param port: 服务的端口号
:return:
"""
stop_appium(port)
cmd = f"appium -p {port}"
logsdir = os.path.join(os.path.dirname(os.path.abspath(__file__)),"logs")
if not os.path.exists(logsdir):
os.mkdir(logsdir)
subprocess.Popen(cmd,shell=True, stdout=open('./logs/'+str(port)+".log",mode='a',encoding="utf8"),
stderr=subprocess.PIPE)
@pytest.fixture(scope='session',autouse=True)
def driver():
# 启动appium服务
start_appium(4723)
desired_caps = {
'platformName': 'Android', # 测试Android系统
'platformVersion': '7.1.2', # Android版本 可以在手机的设置中关于手机查看
'deviceName': '127.0.0.1:62001', # adb devices 命令查看 设置为自己的设备
'automationName': 'UiAutomator2', # 自动化引擎
'noReset': False, # 不要重置app的状态
'fullReset': False, # 不要清理app的缓存数据
'chromedriverExecutable': chromedriver, # chromedriver 对应的绝对路径
'appPackage': "org.cnodejs.android.md", # 应用的包名
'appActivity': ".ui.activity.LaunchActivity" # 应用的活动页名称
}
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_capabilities=desired_caps)
driver.implicitly_wait(5) # 全局的隐式等待时间
yield driver # 将driver 传递出来
# 所有的用例执行之后
stop_appium(4723)
driver.quit()
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object
outcome = yield
# 获取用例的执行结果
rep = outcome.get_result()
# 将执行结果保存到 item 属性中 req.when 执行时
setattr(item, "rep_" + rep.when, rep)
@pytest.fixture(scope='function',autouse=True)
def case_run(driver:webdriver,request):
"""
每个测试用例执行完成之后,如果执行失败截图,截图的名称为测试用例名称+时间格式
:param request:
:return:
"""
yield
if request.node.rep_call.failed:
import os,time
screenshots = os.path.join(os.path.dirname(os.path.abspath(__file__)),'screeshots')
if not os.path.exists(screenshots):
os.mkdir(screenshots)
casename:str = request.node.nodeid
print("执行测试用例的名字:",casename)
# 测试用例的名字
# casename = casename.replace('.py::','_')
filename = time.strftime('%Y_%m_%d_%H_%M_%S')+".png"
screenshot_file = os.path.join(screenshots,filename)
# 保存截图
driver.save_screenshot(screenshot_file)
更多参考:
自动化启动appium服务