目录
appPackage 和appActivity 的获取:连接手机 dos 输入
Pycharm引入插件Appium-Python-Client----关联Appium 和Python
整体知识框架
环境准备 (windows)
1.jdk1.8.0 (64位)
2.android-sdk(直接下载安卓studio就都有了)
3.python:3.7
4.Appium-windows-1.15.1
5.Node.js
//以上安装并配置好环境变量
6.Appium-Python-Client
7.pycharm(用于编写脚本)
8.HTMLTestReportCN(用于生成测试报告)
//以下可选
yaml
//以下两个是为了定时执行用例和发送测试报告——可不用安装
9.Tomcat
10.Jenkins
appium安装和使用
官网地址:https://github.com/appium/appium-desktop/releases/tag/v1.15.1
下载后安装即可
deviceName 可通过adb devices 得到
appPackage 和appActivity 的获取:连接手机 dos 输入
adb shell dumpsys window | findstr mCurrentFocus
Pycharm引入插件Appium-Python-Client----关联Appium 和Python
HTMLTestReportCN----生成测试报告
下载并放入python 目录lib文件夹下
官网:https://github.com/findyou/HTMLTestRunnerCN
HTMLTestReportCN是unittest 拓展插件,二者配合使用
修改后的测试用例代码 :
测试用例二:FirstTest
# 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
from appium import webdriver
import time
import unittest
from HTMLTestRunnerCN import HTMLTestReportCN
caps = {}
caps["platformName"] = "Android"
caps["platformVersion"] = "10"
caps["deviceName"] = "R28M3126C2W"
caps["appPackage"] = "cn.cntv"
caps["appActivity"] = "cn.cntv.ui.activity.SplashActivity"
class FirstTest(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
def tearDown(self) -> None:
self.driver.quit()
def test_start(self):
el1 = self.driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button")
el1.click()
time.sleep(10)
el2 = self.driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_always_button")
el2.click()
time.sleep(10)
el3 = self.driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button")
el3.click()
time.sleep(10)
el4 = self.driver.find_element_by_id("cn.cntv:id/agree")
el4.click()
time.sleep(10)
el5 = self.driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.HorizontalScrollView/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.TextView")
el5.click()
el6 = self.driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.HorizontalScrollView/android.widget.LinearLayout/android.widget.LinearLayout[3]/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.TextView")
el6.click()
el7 = self.driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.HorizontalScrollView/android.widget.LinearLayout/android.widget.LinearLayout[4]/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.TextView")
el7.click()
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(FirstTest)
unittest.TextTestRunner().run(suite)
测试用例二:SecondTest
# 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
from appium import webdriver
import time
import unittest
caps = {}
caps["platformName"] = "Android"
caps["platformVersion"] = "10"
caps["deviceName"] = "R28M3126C2W"
caps["appPackage"] = "cn.cntv.zongyichunwan"
caps["appActivity"] = "cn.cntv.ui.activity.SplashActivity"
#TestCase类,所有测试用例类继承的基本类
class SecondTest(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
def tearDown(self) -> None:
self.driver.quit()
def test_start(self):
el1 = self.driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button")
el1.click()
time.sleep(10)
el2 = self.driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button")
el2.click()
time.sleep(10)
el3 = self.driver.find_element_by_id("com.android.permissioncontroller:id/permission_allow_button")
el3.click()
time.sleep(10)
el4 = self.driver.find_element_by_id("cn.cntv.zongyichunwan:id/dialog_like_ios_certain")
el4.click()
time.sleep(10)
el5 = self.driver.find_element_by_id("cn.cntv.zongyichunwan:id/btnJump")
el5.click()
time.sleep(10)
el6 = self.driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.LinearLayout[1]/android.widget.HorizontalScrollView/android.widget.LinearLayout/android.support.v7.app.ActionBar.Tab[2]/android.widget.RelativeLayout/android.widget.LinearLayout/android.widget.TextView")
el6.click()
time.sleep(10)
el7 = self.driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.support.v4.view.ViewPager/android.widget.RelativeLayout/android.widget.ListView/android.widget.LinearLayout[1]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.ImageView[2]")
el7.click()
time.sleep(10)
self.driver.back()
el8 = self.driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android.widget.FrameLayout[1]/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.LinearLayout[2]/android.support.v4.view.ViewPager/android.widget.RelativeLayout/android.widget.ListView/android.widget.LinearLayout[1]/android.widget.LinearLayout/android.widget.TextView")
el8.click()
time.sleep(10)
self.driver.back()
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(SecondTest)
unittest.TextTestRunner().run(suite)
主测试用例:使用unittest封装多个测试用例
# import os
# os.system("python ./FirstTest.py")
# os.system("python ./SecondTest.py")
import unittest
from FirstTest import FirstTest
from SecondTest import SecondTest
import HTMLTestRunnerCN
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(FirstTest))
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(SecondTest))
# 确定生成报告的路径
filePath = 'D:\ReportCN.html'
fp = open(filePath, 'wb')
# 生成报告的Title,描述
runner = HTMLTestRunnerCN.HTMLTestReportCN(stream=fp, title='自动化测试报告', description='详细测试用例结果', tester='jackron')
runner.run(suite)
yaml数据配置----数据分离
1.参数配置表:desired_caps.yaml
platformName: Android
platformVersion: 5.1.1
deviceName: 127.0.0.1:62025
app: C:\Users\Shuqing\Desktop\Appium software\chapter4\App\kaoyan3.1.0.apk
noReset: False
appPackage: com.tal.kaoyan
appActivity: com.tal.kaoyan.ui.activity.SplashActivity
python文件进行数据读取
rom appium import webdriver
import yaml
file=open('desired_caps.yaml','r')
data=yaml.load(file)
desired_caps={}
desired_caps['platformName']=data['platformName']
desired_caps['platformVersion']=data['platformVersion']
desired_caps['deviceName']=data['deviceName']
desired_caps['app']=data['app']
desired_caps['noReset']=data['noReset']
desired_caps['appPackage']=data['appPackage']
desired_caps['appActivity']=data['appActivity']
driver = webdriver.Remote('http://'+str(data['ip'])+':'+str(data['port'])+'/wd/hub', desired_caps)
日志收集
级别 |
何时使用 |
DEBUG |
调试信息,也是最详细的日志信息。 |
INFO |
证明事情按预期工作。 |
WARNING |
表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。 |
ERROR |
由于更严重的问题,软件已不能执行一些功能了。 |
CRITICAL |
严重错误,表明软件已不能继续运行了。 |
定义日志输出位置和输出格式
#导入logging模块
import logging
logging构成
logging模块包括logger,Handler,Filter,Formatter四个部分。
- Logger 记录器,用于设置日志采集。
- Handler 处理器,将日志记录发送至合适的路径。
- Filter 过滤器,提供了更好的粒度控制,它可以决定输出哪些日志记录。
- Formatter 格式化器,指明了最终输出中日志的格式。
Formatter
使用Formatter对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S。
格式 |
描述 |
%(levelno)s |
打印日志级别的数值 |
%(levelname)s |
打印日志级别名称 |
%(pathname)s |
打印当前执行程序的路径 |
%(filename)s |
打印当前执行程序名称 |
%(funcName)s |
打印日志的当前函数 |
%(lineno)d |
打印日志的当前行号 |
%(asctime)s |
打印日志的时间 |
%(thread)d |
打印线程id |
%(threadName)s |
打印线程名称 |
%(process)d |
打印进程ID |
%(message)s |
打印日志信息
|
logging.basicConfig(filename='runlog.log',level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
PageObject设计模式----代码封装
封装App启动配置信息
desired_caps.py
import yaml
import logging.config
from appium import webdriver
CON_LOG = '../log/log.conf'
logging.config.fileConfig(CON_LOG)
logging = logging.getLogger()
def appium_desired():
stream = open('../yaml/desired_caps.yaml', 'r')
data = yaml.load(stream)
desired_caps={}
desired_caps['platformName']=data['platformName']
desired_caps['platformVersion']=data['platformVersion']
desired_caps['deviceName']=data['deviceName']
desired_caps['app']=data['app']
desired_caps['noReset']=data['noReset']
desired_caps['unicodeKeyboard']=data['unicodeKeyboard']
desired_caps['resetKeyboard']=data['resetKeyboard']
desired_caps['appPackage']=data['appPackage']
desired_caps['appActivity']=data['appActivity']
logging.info('start run app...')
driver = webdriver.Remote('http://'+str(data['ip'])+':'+str(data['port'])+'/wd/hub', desired_caps)
driver.implicitly_wait(8)
return driver
if __name__ == '__main__':
appium_desired()
封装基类:baseview
class BaseView(object):
def __init__(self,driver):
self.driver=driver
def find_element(self,*loc):
return self.driver.find_element(*loc)
封装通用公共类
common_fun.py
from appium_advance.page_object.baseView import BaseView
from selenium.common.exceptions import NoSuchElementException
import logging
from selenium.webdriver.common.by import By
from appium_advance.page_object.desired_caps import appium_desired
class Common(BaseView):
cancelBtn=(By.ID,'android:id/button2')
skipBtn=(By.ID,'com.tal.kaoyan:id/tv_skip')
def check_cancelBtn(self):
logging.info("============check_cancelBtn===============")
try:
element = self.driver.find_element(*self.cancelBtn)
except NoSuchElementException:
logging.info('update element is not found!')
else:
logging.info('click cancelBtn')
element.click()
def check_skipBtn(self):
logging.info("==========check_skipBtn===========")
try:
element = self.driver.find_element(*self.skipBtn)
except NoSuchElementException:
logging.info('skipBtn element is not found!')
else:
logging.info('click skipBtn')
element.click()
if __name__ == '__main__':
driver=appium_desired()
com=Common(driver)
com.check_updateBtn()
com.check_skipBtn()
Windows 中使用批量工具Bat文件运行测试用例
@echo off
appium
pause
@echo off
D:
cd D:\study\PycharmProjects\HelloTest
start python MainTest.py
Python 启动Appium
import subprocess
from time import ctime
def appium_start(host,port):
'''启动appium server'''
bootstrap_port = str(port + 1)
cmd = 'start /b appium -a ' + host + ' -p ' + str(port) + ' -bp ' + str(bootstrap_port)
print('%s at %s' %(cmd,ctime()))
subprocess.Popen(cmd, shell=True,stdout=open('./appium_log/'+str(port)+'.log','a'),stderr=subprocess.STDOUT)
if __name__ == '__main__':
host = '127.0.0.1'
for i in range(2):
port=4723+2*i
appium_start(host,port)
Jenkins 持续集成
jenkins定时构建语法
* * * * *
(五颗星,中间用空格隔开)
第一个*表示分钟,取值0~59
第二个*表示小时,取值0~23
第三个*表示一个月的第几天,取值1~31
第四个*表示第几月,取值1~12
第五个*表示一周中的第几天,取值0~7,其中0和7代表的都是周日
每天下午下班前18点定时构建一次
0 18 * * *
每天早上8点构建一次
0 8 * * *
每30分钟构建一次:
H/30 * * * *
来源:CSDN
作者:jackron2014
链接:https://blog.csdn.net/jackron2014/article/details/104063123