学习airtest+poce笔记01

图像识别和接入poco-SDK

安装 我习惯使用python来跑自动化,有些库得安装下 1、airtest ```python pip install airtest ``` 2、UI自动化框架:poco

pip install pocoui

3、测试框架:pocounit

pip install pocounit

4、Androiddemo下载链接:

先上官网的例子

一、父类

from poco.drivers.unity3d import UnityPoco
from pocounit.case import PocoTestCase
from pocounit.addons.poco.action_tracking import ActionTracker

class MyBaseTestCase(PocoTestCase):
    @classmethod
    def setUpClass(cls):
        super(MyBaseTestCase, cls).setUpClass()
        cls.poco = UnityPoco()

        # 启用动作捕捉(action tracker)
        action_tracker = ActionTracker(cls.poco)
        cls.register_addon(action_tracker)

二、测试用例(继承父类)

# 一个文件里建议就只有一个TestCase
# 一个Case做的事情尽量简单,不要把一大串操作都放到一起
class MyTestCase(MyBaseTestCase):
    def setUp(self):
        # 可以调用一些前置条件指令和预处理指令
        pass

    # 函数名就是这个,用其他名字无效
    def runTest(self):
        '''self.assertEqual相关的断言方法不会收集在测试报告中(网易那边不支持)
           要用self.call_airtest.airtest_api.assert_equal相关方法才会收集在测试报告中
            '''
        # 普通语句跟原来一样
        # self.poco(text='角色').click()

        # 断言语句跟python unittest写法一模一样
        # self.assertTrue(self.poco(text='最大生命').wait(3).exists(), "看到了最大生命")

        # self.poco('btn_close').click()
        # self.poco('movetouch_panel').offspring('point_img').swipe('up')

        start_btn = self.poco('btn_start')
        start_btn.click()
        time.sleep(0.5)
        self.assertEqual(start_btn.get_name(),'btn_start',msg='测试一下断言报告')
        try:
            self.assertEqual(start_btn.get_name(),'btn_start1',msg='测试一下断言报告 1')
        except :pass
        self.try_assert_mothod(self.assertEqual,start_btn.get_name(), 'btn_start1','测试一下断言报告 2')
        basic_btn = self.poco(text='basic')
        basic_btn.click([0.5,0.5])

        self.try_assert_mothod(self.assertEqual,basic_btn.get_name(),'abc','测试一下断言报告 3')

        back_button= self.poco('btn_back',type='Button').focus([1,0.1])
        back_button.click()
        if self.poco(text='drag drop').exists():
            self.poco(text='drag drop').click()
        else:
            back_button.click()

    def tearDown(self):
        # 如果没有*操作,这个函数就不用写出来
        pass

    # 不要写以test开头的函数,除非你知道会发生什么
    # def test_xxx():
    #     pass

if __name__ in '__main__':
    pocounit.main()
    # generate html report
    time_str = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
    simple_report(__file__,output=REPORTPATH/f'test_{time_str}.html',logpath=str(LOGPATH))

实践poco+图像识别

一、封装断言方法

如果正常执行断言方法,失败的话后面的用例会被中断,所以得加上异常兼容;
1、poco的封装

    def poco_assert_mothod(self,func,*args,case_msg=None):
        '''
        :param func: 断言方法
        :param args: 断言方法里需要的参数
        :return: 返回断言结果
        '''
        try:
            if case_msg:
                return func(*args,msg=case_msg)
            else:
                return func(*args)
        except Exception as e:
            print(f'{func} ERROR:', e)
            return False

2、airtest图像识别的封装

    def img_assert_mothod(self,func=None,img_1=None,img_2=None,case_msg='空白说明',threshold=0.8,target_pos=False,rgb=False):
        '''
        :param func: 断言方法,用加括号
        :param args: 断言方法里需要的参数
        :return: 返回断言结果
        '''
        '''
        Template(r"tpl1532588127987.png", record_pos=(0.779, 0.382), resolution=(407, 264), threshold=0.6, target_pos=5, rgb=False)
        threshold:识别精准度
        target_pos:点击坐标偏移
        rgb:色彩识别
                示例:assert_not_exists(self.img_template(img), msg)
                '''
        def img_template(img):
            if not target_pos:
                return Template(self.img_path + img, threshold=threshold, resolution=self.screen_size, rgb=rgb)
            else:
                return Template(self.img_path + img, threshold=threshold, target_pos=target_pos, resolution=self.screen_size, rgb=rgb)
        try:
            if case_msg and img_1 and img_2:
                return func(img_template(img_1),img_template(img_2),case_msg)
            elif case_msg and (img_1 or img_2):
                if img_1:
                    return func(img_template(img_1),case_msg)
                elif img_2:
                    return func(img_template(img_2),case_msg)
            elif case_msg is False:
                return func(img_template(img_1))
        except Exception as e:
            print(f'{func} ERROR:', e)

二、给父类添加ADB的方法

class MyBaseTestCase(PocoTestCase):
    @classmethod
    def setUpClass(cls):
        super(MyBaseTestCase, cls).setUpClass()
        cls.poco = UnityPoco()

        # 启用动作捕捉(action tracker)
        action_tracker = ActionTracker(cls.poco)
        cls.register_addon(action_tracker)
	        self.img_ath = None
	    # AdbShell在之前的的文章里可以找到,封装常用的adb命令
        self.adb = AdbShell()
        self.task_id = None
        if self.check_devices():
            self.screen_size = self.adb.get_screen_size()
            # demo游戏包名
            self.app_name = 'com.NetEase'
            self.app = self.adb.get_thirdparty_app(filter=self.app_name)
        else:raise ConnectionError
        # 获取操作系统
        self.system = os.name

    def check_devices(self):
        if self.adb.getDevices() is not False:
            return True
        else:
            self.adb.adb('adb kill-server')
            self.adb.adb('adb start-server')

三、poco常用方法

    def __doc__(self):
        '''选择UI对象'''
        self.poco('')
        # select by node name
        self.poco('bg_mission')
        # select by name and other properties
        self.poco('bg_mission', type='Button')
        self.poco(textMatches='^据点.*$', type='Button', enable=True) #加上对应属性来定位
        # select by direct child/offspring
        self.poco('main_node').child('list_item').offspring('item')
        # 顺序选择
        items = self.poco('main_node').child('list_item').offspring('item')
        print(items[0].child('material_name').get_text())
        # 迭代遍历一组UI
        items = self.poco('main_node').child('list_item').offspring('item')
        for item in items:
            item.child('icn_item')

        '''读取属性'''
        mission_btn = self.poco('bg_mission')
        print(mission_btn.attr('type'))  # 'Button'
        print(mission_btn.get_text())  # '获取text'
        print(mission_btn.attr('text'))  # equivalent to .get_text()
        print(mission_btn.exists())  # True/False, exists in the screen or not

        '''操作UI对象'''
        # 点击
        self.poco('bg_mission').click()
        self.poco('bg_mission').click('center')
        self.poco('bg_mission').click([0.5, 0.5])  # equivalent to center
        self.poco('bg_mission').focus([0.5, 0.5]).click()  # equivalent to above expression
        self.poco()
        # 滑动
        joystick = self.poco('movetouch_panel').child('point_img')
        joystick.swipe('up')
        joystick.swipe([0.2, -0.2])  # swipe sqrt(0.08) unit distance at 45 degree angle up-and-right
        joystick.swipe([0.2, -0.2], duration=0.5)
        # 拖拽
        self.poco(text='突破芯片').drag_to(self.poco(text='岩石司康饼'))
        # 等待
        self.poco('bg_mission').wait(5).click()  # wait 5 seconds at most,click once the object appears
        self.poco('bg_mission').wait(5).exists()  # wait 5 seconds at most,return Exists or Not Exists
        self.poco().wait_for_appearance() # 等待目标出现,超时raises PocoTargetTimeout
        self.poco().wait_for_disappearance() # 等待目标消失,超时raises PocoTargetTimeout
        # self.poco.wait_for_any()
        # self.poco.wait_for_all()

        '''全局操作'''
        # 点击
        self.poco.click([0.5, 0.5])  # click the center of screen
        self.poco.long_click([0.5, 0.5], duration=3)
        # swipe from A to B
        point_a = [0.1, 0.1]
        center = [0.5, 0.5]
        self.poco.swipe(point_a, center)
        # 滑动
        direction = [0.1, 0]
        self.poco.swipe(point_a, direction=direction)
        # 截屏
        from base64 import b64decode
        b64img, fmt = self.poco.snapshot(width=720)
        open('screen.{}'.format(fmt), 'wb').write(b64decode(b64img))

四、商店测试用例

SDK还没有接好,目前是用图像识别的方式写个demo

class TestShop(MyBaseTestCase):
    '''
    用例设计参考思维导图的测试用例
    '''
    def setUp(self):
        self.call_airtest.img_path = Path(__file__).parent / 'imgFolder'

    def close_tips(self):
        tips_1 = self.call_airtest.img_assert_mothod(exists,'goods_tips_close_btn.png',case_msg=False)
        tips_2 = self.call_airtest.img_assert_mothod(exists,'rank_close_btn.png',target_pos=3,case_msg=False)
        if tips_1:
            touch(tips_1)
        if tips_2:
            touch(tips_2)
    def runTest(self):
        self.close_tips()
        '''用例执行方法在这里'''
        self.entrance('shop_icon_1.png', 'shop_icon_2.png', 'shop_homepage.png')
        self.shop_type('yuanbao_shop.png', 'duihuan_shop.png','jipin_shop.png','jifen_shop.png')
        self.title('shop_tag_1.png','shop_tag_2.png','shop_tag_3.png')
        # 购买多个商品,图片坐标偏移8
        shop_goods_list = [
            ('银两','yinliang.png','yinliang_max.png',5),
            ('福袋碎片','fudai.png','fudai_max.png',1),
            ('5级宝石', 'baoshi5.png', 'baoshi5_max.png', 5),
            ('兽丹礼包', 'shoudan.png', 'shoudan_max.png', 5),
        ]
        for test_data in shop_goods_list:
            self.gold_daily_shop(*test_data)

    def tearDown(self):
        # 如果没有*操作,这个函数就不用写出来
        pass

    # 判断入口
    def entrance(self,enter_img_1=None,enter_img_2=None,shop_homepage=None):
        shop_icon = self.call_airtest.img_assert_mothod(assert_exists,enter_img_1,case_msg='显示商店图标')
        if shop_icon:
            touch(shop_icon)
            sleep(1.5)
            self.call_airtest.img_assert_mothod(assert_exists,shop_homepage,case_msg='进入后出现商品页签')
        else:
            wait_shop_icon = wait(Template(self.call_airtest.img_path+enter_img_2),5)
            if wait_shop_icon:
                touch(wait_shop_icon)
                self.call_airtest.img_assert_mothod(assert_exists,shop_homepage,case_msg='进入后出现商品主页')
            else:
                raise TargetNotFoundError

    def shop_type(self,type_1,type_2,type_3,type_4):
        '''各个商城'''
        self.shop_type_1 = self.call_airtest.img_assert_mothod(assert_exists,type_1,case_msg='显示元宝商城')
        self.shop_type_2 = self.call_airtest.img_assert_mothod(assert_exists,type_2,case_msg='显示兑换商城')
        self.shop_type_3 = self.call_airtest.img_assert_mothod(assert_exists,type_3,case_msg='显示*商城')
        self.shop_type_4 = self.call_airtest.img_assert_mothod(assert_exists,type_4,case_msg='显示积分商城')

    def title(self,shop_tag_1,shop_tag_2,shop_tag_3):
        '''页签'''
        self.shop_tag_1 = self.call_airtest.img_assert_mothod(assert_exists,shop_tag_1,case_msg='显示每日特惠页签')
        self.shop_tag_2 = self.call_airtest.img_assert_mothod(assert_exists,shop_tag_2,case_msg='显示常用道具页签')
        self.shop_tag_3 = self.call_airtest.img_assert_mothod(assert_exists,shop_tag_3,case_msg='显示特权商城页签')

    def gold_daily_shop(self,goods,goods_img,goods_max_img,buy_max):
        '''商店购买'''
        # 点击元宝商城
        if self.shop_type_1:
            touch(self.shop_type_1)
            # 点击每日特惠
            if self.shop_tag_1:
                touch(self.shop_tag_1)
        else:
            print('入口目标没有找到,调整截图或降低识别率')
            raise TargetNotFoundError
        # self.call_airtest.img_assert_mothod(assert_exists,cost_img,case_msg=f'{goods}道具价格')
        # 商品
        self.goods_pos = self.call_airtest.img_assert_mothod(assert_exists,goods_img,target_pos=8,case_msg=f'显示{goods}道具')
        # swipe(self.goods_pos,vector=(0.5,0.8))
        if self.goods_pos:
            # 限购
            for i in range(buy_max):
                touch(self.goods_pos)
            # 滑动到底部
            # 滑动一次接近翻一页
            self.swipe_up_pos = (520,1910),(520,607)
            swipe(*self.swipe_up_pos)
            swipe(*self.swipe_up_pos)
            sleep(1)
            self.goods_max_pos = self.call_airtest.img_assert_mothod(assert_exists,goods_max_img,case_msg=f'{goods}购买{buy_max}次后,达到上限灰化')
            # 划回去
            self.swipe_down_pos = (520,607),(520,1910)
            swipe(*self.swipe_down_pos)
            swipe(*self.swipe_down_pos)
            sleep(1)

上一篇:数据结构-栈和队列


下一篇:post_04_assert