测试开发笔记六(移动端app自动化测试)

2020-05-18  本文已影响0人  提摩太_e9ec

01 | Appium环境安装


appium生态工具

环境安装

02 | Appium用例录制


android自动化依赖

具体操作

获取app的信息

03 | 元素定位与隐式等待


Capability设置

by_accessibility_id

driver.find_element_by_accessibility_id("content-desc")

三种经典等待方式

示例

from time import sleep

from appium import webdriver

desired_caps = {
    "platformName": "Android",
    "deviceName": "127.0.0.1:7555",
    "platformVersion": "6.0",
    "appPackage": "com.xueqiu.android",
    "appActivity": ".view.WelcomeActivityAlias",
    "noReset": "true",
    "dontStopAppOnReset": "true",
    "skipDeviceInitialization": "true"
}

driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
driver.implicitly_wait(10)
driver.find_element_by_id("com.xueqiu.android:id/tv_search").click()
driver.find_element_by_id("com.xueqiu.android:id/search_input_text").send_keys("alibaba")
driver.find_element_by_accessibility_id("content-desc")
driver.back()
driver.back()
sleep(3)
driver.quit()

04 | app控件定位


android基础知识

ios基础知识

dom结构解读

id、aid、xpath定位方法

uiautomatorviewer定位工具使用

我的uiautomatorviewer识别的屏幕是横屏的,需要保存到本地,转成竖屏再导入,挺麻烦的,如果是这样,不如用inspector了

示例

from time import sleep
from appium import webdriver


class TestDW:
    def setup(self):
        desired_caps = {
            "platformName": "Android",
            "deviceName": "127.0.0.1:7555",
            "platformVersion": "6.0",
            # "appPackage": "com.xueqiu.android",
            # "appActivity": ".view.WelcomeActivityAlias",
            "noReset": "true",
            "dontStopAppOnReset": "true", 
            "skipDeviceInitialization": "true",
            "unicodeKeyBoard": "true",
            "resetKeyBoard": "true"
        }

        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        self.driver.back()
        # self.driver.quit()

    def test_search(self):
        """
        1.打开雪球app
        2.点击搜索输入框
        3.搜索输入框输入“阿里巴巴”
        4.搜索结果中选择“阿里巴巴”并点击
        5.获取阿里巴巴的股价,并判断价格>200
        """
        self.driver.find_element_by_id("com.xueqiu.android:id/tv_search").click()
        self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text").send_keys("阿里巴巴")
        self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/name' and @text='阿里巴巴']").click()
        current_price = float(self.driver.find_element_by_id("com.xueqiu.android:id/current_price").text)
        assert current_price > 200
        sleep(3)

05 | app控件交互


元素的常用方法

元素的常用属性

案例

from time import sleep
from appium import webdriver


class TestDW:
    def setup(self):
        desired_caps = {
            "platformName": "Android",
            "deviceName": "127.0.0.1:7555",
            "platformVersion": "6.0",
            # "appPackage": "com.xueqiu.android",
            # "appActivity": ".view.WelcomeActivityAlias",
            "noReset": "true",
            "dontStopAppOnReset": "true", 
            "skipDeviceInitialization": "true",
            "unicodeKeyBoard": "true",
            "resetKeyBoard": "true"
        }

        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        self.driver.back()
        # self.driver.quit()

    def test_atrr(self):
        """
        1.打开雪球首页
        2.定位首页搜索框
        3.判断搜索框是否可用,并打印搜索框name属性值
        4.打印搜索框左上角坐标和它的宽高
        5.向搜索框输入alibaba
        6.判断【阿里巴巴】是否可见
        7.如果可见,打印“搜索成功”,如果不可见,打印“搜索失败”
        """
        search = self.driver.find_element_by_id("com.xueqiu.android:id/tv_search")
        search_enabled = search.is_enabled()
        print(search.text)
        print(search.location)
        print(search.size)
        if search_enabled == True:
            search.click()
            self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text").send_keys("alibaba")
            alibaba_element = self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/name' and @text='阿里巴巴']")
            # alibaba_element.is_displayed()
            element_display = alibaba_element.get_attribute("displayed")
            if element_display == "true":
                print("搜索成功")
            else:
                print("搜素失败")

06 | 触屏操作自动化


TouchAction

案例

from time import sleep
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction


class TestTouchAction:
    def setup(self):
        desired_caps = {
            "platformName": "Android",
            "deviceName": "127.0.0.1:7555",
            "platformVersion": "6.0",
            # "appPackage": "com.xueqiu.android",
            # "appActivity": ".view.WelcomeActivityAlias",
            "noReset": "true",
            "dontStopAppOnReset": "true",  
            "skipDeviceInitialization": "true",
            "unicodeKeyBoard": "true",
            "resetKeyBoard": "true"
        }

        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        pass
        # self.driver.back()
        # self.driver.quit()

    def test_atrr(self):
        action = TouchAction(self.driver)
        # action.press(x=386.5,y=1076.3).wait(200).move_to(x=386.5,y=519.5).release().perform()
        window_rect = self.driver.get_window_rect()
        width = window_rect['width']
        height = window_rect['height']
        x1 = int(width / 2)
        y_start = int(height * 4 / 5)
        y_end = int(height * 1 / 5)
        action.press(x=x1, y=y_start).wait(200).move_to(x=x1, y=y_end).release().perform()

07 | 高级定位


xpath定位进阶

uiautomator定位表达式(一般不用)

滑动定位

from time import sleep
from appium import webdriver


class TestDW:
    def setup(self):
        desired_caps = {
            "platformName": "Android",
            "deviceName": "127.0.0.1:7555",
            "platformVersion": "6.0",
            "appPackage": "com.xueqiu.android",
            "appActivity": ".view.WelcomeActivityAlias",
            "noReset": "true",
            # "dontStopAppOnReset": "true", 
            "skipDeviceInitialization": "true",
            "unicodeKeyBoard": "true",
            "resetKeyBoard": "true"
        }

        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        self.driver.back()
        # self.driver.quit()

    def test_scroll_find(self):
        self.driver.find_element_by_android_uiautomator('new UiSelector().text("关注")').click()
        self.driver.find_element_by_android_uiautomator('new UiScrollable( new UiSelector().'
                                                        'scrollable(true).instance(0)).'
                                                        'scrollIntoView(new UiSelector().text("美股马甲")'
                                                        '.instance(0))').click()
        sleep(5)

08 | 显示等待机制


强制等待

隐式等待

显示等待

expected_condition

案例

from time import sleep
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


class TestDW:
    def setup(self):
        desired_caps = {
            "platformName": "Android",
            "deviceName": "127.0.0.1:7555",
            "platformVersion": "6.0",
            "appPackage": "com.xueqiu.android",
            "appActivity": ".view.WelcomeActivityAlias",
            "noReset": "true",
            # "dontStopAppOnReset": "true",  
            "skipDeviceInitialization": "true",
            "unicodeKeyBoard": "true",
            "resetKeyBoard": "true"
        }

        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        self.driver.back()
        # self.driver.quit()

    def test_search(self):
        self.driver.find_element_by_id("com.xueqiu.android:id/tv_search").click()
        self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text").send_keys("alibaba")
        self.driver.find_element_by_xpath("//*[@resource-id='com.xueqiu.android:id/name' and @text='阿里巴巴']").click()

        locator = (MobileBy.XPATH, "//*[@text='09988']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']")
        # WebDriverWait(self.driver, 10).until(expected_conditions.element_to_be_clickable(locator))
        ele = WebDriverWait(self.driver, 10).until(lambda x: x.find_element(*locator))
        # ele = self.driver.find_element(*locator)
        print(ele.text)
        current_price = float(ele.text)
        expect_price = 170
        assert current_price > expect_price
        sleep(3)

09 | toast控件识别


toast定位

示例

driver.page_source
driver.find_element(MobileBy.XPATH,"//*[@class='android.widget.Toast']").text
driver.find_element(MobileBy.XPATH,"//*[contains(@text,'Clicked popup')]").text

10 | 属性获取与断言


get atrribute原理分析

search_ele = self.driver.find_element_by_id("com.xueqiu.android:id/tv_search")
print(search_ele.get_attribute("content-desc"))
print(search_ele.get_attribute("enabled"))
print(search_ele.get_attribute("clickable"))

断言

a = 10
b = 20
assert a > b # 若断言失败,其后的断言将不会执行
assert 'h' in 'this'
assert_that(10,equal_to(9),'这是一个提示')
assert_that(13,close_to(10,2))

11 | appium参数化用例


案例

from time import sleep
import pytest
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from hamcrest import *


class TestDW:
    def setup(self):
        desired_caps = {
            "platformName": "Android",
            "deviceName": "127.0.0.1:7555",
            "platformVersion": "6.0",
            "appPackage": "com.xueqiu.android",
            "appActivity": ".view.WelcomeActivityAlias",
            "noReset": True,
            # "dontStopAppOnReset": True,
            "skipDeviceInitialization": True,
            "unicodeKeyBoard": "true",
            "resetKeyBoard": "true"
        }

        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        self.driver.find_element(MobileBy.ID, 'com.xueqiu.android:id/action_close').click()
        # self.driver.back()
        # self.driver.quit()

    @pytest.mark.parametrize('searchkey,type,expect_price', [
        ('alibaba', 'BABA', 190),
        ('xiaomi', '01810', 10)
    ])
    def test_search(self, searchkey, type, expect_price):
        self.driver.find_element_by_id("com.xueqiu.android:id/tv_search").click()
        self.driver.find_element_by_id("com.xueqiu.android:id/search_input_text").send_keys(searchkey)
        self.driver.find_element_by_xpath(f"//*[@text='{type}']").click()

        current_price = self.driver.find_element(MobileBy.XPATH,
                                                 f"//*[@text='{type}']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']").text
        current_price_float = float(current_price)
        # expect_price = 180
        assert_that(current_price_float, close_to(expect_price, expect_price * 0.2))
        sleep(3)

12 | 数据驱动


https://github.com/tim8709/hogwarts_testing/tree/master/test_appium

13 | Android WebView测试

image.png

纯网页应用

from appium import webdriver
from time import sleep

class TestBrowser():
    def setup(self):
        des_caps = {
            'platformName': 'android',
            'platformVersion': '6.0',
            'browserName': 'Browser',
            'noRest': True,
            'deviceName': '127.0.0.1:7555',
            'skipServerInstallation': 'true',
            'chromedriverExecutableDir': 'xxx', # 路径下可放多个webdriver
            'chromedriverExecutable': 'D:\workspace\hogwarts\dirver\chromedriver2.24.exe'  # 指定Chromedriver存放的位置
        }
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", des_caps)
        self.driver.implicitly_wait(10)

    def teardown(self):
        # self.driver.quit()
        pass
    
    def test_browser(self):
        self.driver.get("http://www.baidu.com")
        sleep(5)

android混合页面测试

self.driver.find_element(MobileBy.ACCESSIBILITY_ID,'xxx')

2.切换上下文定位

# 进入webview页面后
print(self.driver.contexts)
self.driver.switch_to.context(self.driver.contexts[-1])
print(self.driver.page_source)

print(self.driver.window_handles)
self.driver.switch_to.window(self.driver.window_handles[-1])

3.若知道html的地址,可用浏览器直接访问(不稳定)
4.adb logcat -v time | grep http 查找当前页面地址

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
        Webview.setWebContentsDebuggingEnabled(true);
}

14 | 实战1


appium的设计理念

image.png

连接真机&模拟器

测试苹果机需要的环境

模拟器

模拟器安装卸载应用

adb常用命令

15 | 实战2


常用的接口信息

adb

image.png

元素定位

企业微信

from time import sleep
import pytest
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy


class TestBrowser():

    def setup_class(self):
        des_caps = {
            'platformName': 'android',
            'deviceName': '127.0.0.1:7555',
            'appPackage': 'com.tencent.wework',
            'appActivity': '.launch.WwMainActivity',
            'noReset': True,
            'chromedriverExecutable': 'D:\workspace\hogwarts\dirver\chromedriver2.24.exe'  # 指定Chromedriver存放的位置
        }
        self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", des_caps)
        self.driver.implicitly_wait(10)

    def teardown_class(self):
        self.driver.quit()

    # def setup(self):
    #     pass
    #
    # def teardown(self):
    #     self.driver.back()

    # @pytest.fixture()
    # def add_fixture(self):
    #     yield
    #     self.driver.back()

    @pytest.mark.parametrize('name,gender,phone', [
        ('姓名16', '男', '13200000016'),
        ('姓名17', '男', '13200000017')
    ])
    def test_add_member(self, add_fixture, name, gender, phone):
        # name = "姓名6"
        # gender = "男"
        # phone = "13211111116"
        # 进入通讯录
        self.driver.find_element(MobileBy.XPATH, '//*[@text="通讯录"]').click()
        # 滚动查找“添加成员”
        self.driver.find_element_by_android_uiautomator('new UiScrollable( new UiSelector().'
                                                        'scrollable(true).instance(0)).'
                                                        'scrollIntoView(new UiSelector().text("添加成员")'
                                                        '.instance(0))').click()
        # 手动添加
        self.driver.find_element(MobileBy.ID, "com.tencent.wework:id/c7g").click()

        current_act = self.driver.current_activity
        assert ".contact.controller.ContactAddActivity" in current_act

        self.driver.find_element(MobileBy.XPATH, '//*[contains(@text,"姓名")]/../*[@text="必填"]').send_keys(name)
        self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/dux').click()
        sleep(1)
        if gender == "男":
            self.driver.find_element(MobileBy.XPATH, '//*[@text="男"]').click()
        else:
            self.driver.find_element(MobileBy.XPATH, '//*[@text="女"]').click()

        self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/eq7').send_keys(phone)
        self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/gur').click()
        sleep(1)
        # print(self.driver.page_source)
        assert "添加成功" in self.driver.find_element(MobileBy.XPATH, '//*[@text="添加成功"]').text

    @pytest.mark.parametrize('name', [
        '姓名5', '姓名7'
    ])
    def test_delete_member(self, name):
        self.driver.find_element(MobileBy.XPATH, '//*[@text="通讯录"]').click()
        self.driver.find_element(MobileBy.XPATH, f'//*[@text="{name}"]').click()
        self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/guk').click()
        self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/azd').click()
        self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/duq').click()
        self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/b_4').click()
        sleep(3)
        deleted_member = self.driver.find_elements(MobileBy.XPATH, f'//*[@text="{name}"]')
        assert len(deleted_member) == 0

    def test_delete_member2(self):
        self.driver.find_element(MobileBy.XPATH, '//*[@text="通讯录"]').click()
        while True:
            members = self.driver.find_elements(MobileBy.XPATH, '//*[contains(@text,"姓名")]')
            if len(members) ==0:
                print("没有要删除的成员了")
                break
            text = members[0].text
            members[0].click()
            self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/guk').click()
            self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/azd').click()
            self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/duq').click()
            self.driver.find_element(MobileBy.ID, 'com.tencent.wework:id/b_4').click()
            sleep(3)
            assert text not in self.driver.page_source

16 | 实战3(PO设计模式在Appium中的应用)


PageObject设计原则

代码

https://github.com/tim8709/hogwarts_testing/tree/master/test_appium/page_object2

上一篇 下一篇

猜你喜欢

热点阅读