python3 + uiautomator2 achieve POM (micro-channel automated test applet) QQ exchange group 822,659,419

Various SeleniumPOM- framework in line to see, not asking many of POM uiautomator2, so I decided to write a uiautomator2 of POM.

First introduced what is POM ( excerpt )

Unit testing framework in Python unittest, after all our test class files are used to assist us to debug unittest and script development. Get debug mechanism and determine the unittest to create and manage our automated test scripts, then we come under consideration, the framework design a very common design -POM (Page Object Model)

POM, Chinese letters mean, the page object model, POM is a very popular in recent years, automatic test pattern, or thinking, POM is not a framework, is a problem-solving ideas. Using POM aim is to solve the front-end UI changes frequently, resulting in automated test script maintenance costs increasing.

POM design ideas and take the difference is not taken, the left side of the page elements and test code are written in a class file, if you need to change the page, then they would have to modify the positioning of page elements, so you want to modify the class in the test code, this look up and confusion. Right after taking POM, the main difference is that the separate page elements and test scripts and business logic out to two different types of documents. ClassA write-only page element positioning, packaging and business logic code operation, ClassB just write test scripts, do not care how elements positioned just write code to call the ClassA to cover the different test scenarios. If the front page changes only need to modify the positioning element ClassA, without the need to modify the test script code in ClassB.

POM has the following advantages:

1. The web ui object repository separate from the test scripts, test scripts and business code separation.

2. Each page corresponds to a page class, the elements of the page write page class.

3. page class includes locating the page elements, and these elements and associated operational code wrapping method.

4. The code reuse, thereby reducing the amount of the test script code.

5. The level of clarity, while supporting multiple writing automated script development, for example, each person write a few pages which do not affect others.

6. Recommends page class and business logic methods gave a meaningful name for others to quickly write scripts and script maintenance.

About the base class is defined as: the operation of some of the common selenium page package to base_page.py the class file after each page of the POM class, you inherit this base class, so that each class has a base class page Methods

Then describes the implementation of the next lower uiautomator2 POM

  1. Create a folder to find out the contents of each folder storage
framework:代码复用,从而减少测试脚本代码量
logs:运行日志
modules:业务代码
screenshots:测试失败截图
testsuites:测试脚本
test_report:测试报告
tools:其他第三方库

Here Insert Picture Description
2. Revenue Code (modules)
entrance.py

# coding=utf-8
import time
import unittest
import uiautomator2  as u2
from framework.failed import Failed
from framework.logger import Logger

logger = Logger(logger="BrowserEngine").getlog()


d = u2.connect()
#d = u2.connect('192.168.1.173')

now=time.strftime("%Y%m%d%H%M%S",time.localtime())

class Entrance(unittest.TestCase):

    def entrance_test(self):
        logger.info("执行进入小程序.")
        print(now + ":" + "进入小程序")
        d.app_start("com.tencent.mm")
        logger.info("打开微信.")
        time.sleep(1)
        while True:
            logger.info("判断是否到微信主界面.")
            if d(resourceId="com.tencent.mm:id/jb").exists:
                logger.info("当前在微信主界面,执行测试微信小程序.")
                d(resourceId="com.tencent.mm:id/jb").click()
                time.sleep(1)
                d(text=u'搜索').set_text("火眼看看")
                time.sleep(1)
                d(resourceId="com.tencent.mm:id/qm").click()
                time.sleep(2)
                '''
                while True:

                    if d.xpath("//android.widget.TextView[@text='拍照识别']").exists:
                        logger.info("已经到达识别界面")
                        break
                    else:
                        logger.info("进入小程序不是识别界面,寻找识别界面")

                        d.press("back")
                        time.sleep(2)

                    # 断言
                    if (d(text=u"点我了解").exists):
                        print(now + ":" + '进入小程序成功')
                    else:
                        print(now + ":" + '进入小程序失败')
                        Failed.failed_test(self)
                        '''

                break
            else:
                logger.info("在非微信主界面,执行返回.")
                d.press("back")
                time.sleep(1)

3. reusability of code (Framework)

And the execution result failure theme labeled with cases of failure ( failed.py )

# coding=utf-8
import time
import unittest
import os
import uiautomator2  as u2
from framework.logger import Logger


logger = Logger(logger="BasePage").getlog()
d = u2.connect()
#d = u2.connect('192.168.1.173')

now=time.strftime("%Y%m%d%H%M%S",time.localtime())

class Failed(unittest.TestCase):
    def failed_test(self):
        logger.error("出现错误!" )
        now = time.strftime("%Y%m%d%H%M%S", time.localtime())
        report_path = os.path.dirname(os.path.abspath('.')) + '/screenshots/'
        picture = report_path + now + "error.jpg"
        d.screenshot(picture)
        a = "P"
        b = "F"
        self.assertEqual(a, b)


Determine whether the need to unlock the phone ( lock.py )

# coding=utf-8
import time
import unittest
import uiautomator2  as u2
from framework.logger import Logger

logger = Logger(logger="BrowserEngine").getlog()



d = u2.connect()
#d = u2.connect('192.168.1.173')

now=time.strftime("%Y%m%d%H%M%S",time.localtime())

class Lock(unittest.TestCase):
    def  lock_test(self):  #手机屏幕解锁
        logger.info("检查是否需要解锁.")
        if d(resourceId="com.smartisanos.keyguard:id/desk_kg").exists:  #检查是否存在灭屏状态的元素属性
            logger.info("需要解锁.")
            d.screen_on()
            time.sleep(3)
            d.swipe_points([(0.485, 0.708), (0.481, 0.286)], 0.05)  # 滑动解锁界面
            time.sleep(1)
            d.swipe_points([(0.762, 0.394), (0.489, 0.525), (0.777, 0.529), (0.503, 0.651), ], 0.05)  # 解九宫锁
            time.sleep(1)
            logger.info("解锁成功.")
        else:
            logger.info("当前未锁屏,无需解锁.")



Run Log ( logger.py )

# _*_ coding: utf-8 _*_
import logging
import os.path
import time


class Logger(object):
    def __init__(self, logger):
        '''''
            指定保存日志的文件路径,日志级别,以及调用文件
            将日志存入到指定的文件中
        '''

        # 创建一个logger
        self.logger = logging.getLogger(logger)
        self.logger.setLevel(logging.DEBUG)

        # 创建一个handler,用于写入日志文件
        rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))
        # log_path = os.path.dirname(os.getcwd()) + '/Logs/'  # 项目根目录下/Logs 保存日志
        log_path = os.path.dirname(os.path.abspath('.')) + '/logs/'
        # 如果case组织结构式 /testsuit/featuremodel/xxx.py , 那么得到的相对路径的父路径就是项目根目录
        log_name = log_path + rq + '.log'
        fh = logging.FileHandler(log_name)
        fh.setLevel(logging.INFO)

        # 再创建一个handler,用于输出到控制台
        ch = logging.StreamHandler()
        ch.setLevel(logging.INFO)

        # 定义handler的输出格式
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)

        # 给logger添加handler
        self.logger.addHandler(fh)
        self.logger.addHandler(ch)

    def getlog(self):
        return self.logger

Slide the screen to find the target ( sliding.py )

# coding=utf-8
import time
import unittest
import uiautomator2  as u2
from framework.failed import Failed

from framework.logger import Logger

logger = Logger(logger="BrowserEngine").getlog()


d = u2.connect()
#d = u2.connect('192.168.1.173')

now=time.strftime("%Y%m%d%H%M%S",time.localtime())

class Sliding(unittest.TestCase):



    def sliding_test(self):

        logger.info("滑动查找目标.")
        print(now + ":" + "滑动开始")
        count=1

        while  count<=3:
            print('第', count, "次滑动.")
            count=count+1
            logger.info("滑动查找目标")
            if d(className="android.view.View123", instance=450).exists:
                logger.info("找到目标")
                time.sleep(1)
                logger.info('查看目标属性.')
                d(className="android.view.View", instance=450).click()
                time.sleep(3)

                if d(text=u"最大宽度:").exists:
                    print(now + ":" + '查看病害属性成功')
                    time.sleep(3)

                else:
                    print(now + ":" + '查看属性成失败')
                    time.sleep(3)
                    Failed.failed_test(self)
                    time.sleep(3)
                break
            else:
                logger.info('未找到目标,继续滑动查找.')
                d.swipe_points([(0.457, 0.674), (0.465, 0.336) ], 0.08)  # 滑动界面
                time.sleep(3)


  1. Test Script (testsuites)
    use case script (test_relicl.py)
# coding=utf-8
import time
import unittest
import uiautomator2  as u2
from modules.entrance import Entrance
from framework.lock import Lock
from modules.location import Location
from modules.identification import Identification
from framework.logger import Logger

logger = Logger(logger="BrowserEngine").getlog()







d = u2.connect()
#d = u2.connect('192.168.1.173')


class Relicl(unittest.TestCase):

    #@classmethod
    def setUp(self):
        self.watcherson()
        #Lock.test_lock(self)
        print  ("----------SetUp -----\n")

    #@classmethod
    def tearDown(self):
        d.watchers.remove()
        print  ("-----------TearDown----\n")
    def watcherson(self):
        d.watcher(u'注意').when(text=u'你在此次选择后可以到“手机管理 - 权限管理”中修改此项设置').click(text=u'允许', className='android.widget.Button',resourceId='android:id/button1')
        d.watcher(u'无响应').when(text=u'关闭应用').click(text=u'关闭应用', className='android.widget.Button')
        d.watcher(u'删除').when(description=u'关闭').click(description=u'关闭', className='android.widget.ImageView',resourceId='com.android.mms:id/quick_message_close_sign')
        d.watcher(u'关闭').when(description=u'关闭').click(description=u'关闭', className='android.widget.ImageView',resourceId='com.android.systemui:id/pop_up_dialog_quick_message_close_sign')

        d.watchers.run()
        pass
    def test_entrance(self):
        Lock.lock_test(self)
        Entrance.entrance_test(self)
        while True:
            logger.info("尝试执行选择位置")
            try:
                Location.location_test(self)
                logger.info("可以执行")
                break
            except:
                logger.info("不能执行选择位置,寻找选择位置界面继续执行")
                d.press("back")

    def test_identification(self):
        logger.info("开始执行识别")
        for count in list(range(1,6)):
            Identification.identification_test(self)


Start test code ( TestRunner.py )

# coding=utf-8
import HTMLTestRunner
import os
import unittest
import time



if __name__ =='__main__':
    suite = unittest.TestLoader().discover("testsuites")
    # 初始化一个HTMLTestRunner实例对象,用来生成报告

    # 设置报告文件保存路径
    report_path = os.path.dirname(os.path.abspath('.')) + '/test_report/'
    # 获取系统当前时间
    now = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time()))
    # 设置报告名称格式
    HtmlFile = report_path + now + "HTMLtemplate.html"
    fp = open(HtmlFile, "wb")
    # 构建suite

    runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u"自动化测试报告", description=u"用例测试情况")
    # 开始执行测试套件
    runner.run(suite)

    fp.close()


Run Results
Here Insert Picture Description
Test logtesting report

Published 58 original articles · won praise 18 · views 20000 +

Guess you like

Origin blog.csdn.net/qq_42846555/article/details/89378190