Android automated testing --Appium + python + Jenkins automated testing framework to build

table of Contents

 

Overall knowledge framework

Preparing the Environment (windows)

appium install and use

adb devices may be obtained by deviceName

appPackage and appActivity acquisition: Connect the phone dos input

 Pycharm plug Appium-Python-Client associated Appium and introducing ---- Python

 ​

 HTMLTestReportCN ---- generate test reports

The revised test codes:

Test Case two: FirstTest

Test Case two: SecondTest

Main test: using a plurality of test package unittest

Data Configuration data separation yaml ----

Log Collection

logging constitution

---- Code Package Design mode PageObject

App startup configuration package 

Package base class: baseview 

 

General Public class package 

Windows tool used in the batch file to run test cases Bat

Python start Appium

Jenkins Continuous Integration


Overall knowledge framework

Preparing the Environment (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 install and use

Official website address: https://github.com/appium/appium-desktop/releases/tag/v1.15.1

You can download and install

adb devices may be obtained by deviceName

 

appPackage and appActivity acquisition: Connect the phone dos input

adb shell dumpsys window | findstr mCurrentFocus

 Pycharm plug Appium-Python-Client associated Appium and introducing ---- Python

 

 HTMLTestReportCN ---- generate test reports

Download python and placed in the directory lib folder

Official website: https://github.com/findyou/HTMLTestRunnerCN

HTMLTestReportCN is unittest expand plug-in, both with the use of

The revised test codes:

Test Case two: 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)

Test Case two: 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)

 

Main test: using a plurality of test package 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)

Data Configuration data separation yaml ----

Table 1. Parameter Configuration: 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 file read data

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)

 

Log Collection

level

When to Use

DEBUG

Debugging information, it is the most detailed log information.

INFO

Prove things work as expected.

WARNING

Show that there have been some accidents or problems (such as 'disk full') will occur in the near future. Or in the software work properly.

ERROR

Due to more serious problems, the software can not perform some of the functions.

CRITICAL

A serious error, indicating that the software can not continue to run.

 Define the log output position and the output format

#导入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 * * * *

 

 

 

发布了58 篇原创文章 · 获赞 4 · 访问量 4万+

Guess you like

Origin blog.csdn.net/jackron2014/article/details/104063123