20230528-App自动化训练营二

标题

App 企业微信实战

PPT

App自动化训练营二

课程价值

  • 了解 PO模式
  • 使用 PO 模式封装框架

大纲

  • 元素定位
  • PO模式介绍
  • 企业微信实战2

脚本编写

应用

PO 封装

  • 方法意义
    • 用公共方法代表UI所提供的服务
    • 方法应该返回其他的PageObject或者返回用于断言的数据
    • 同样的行为不同的结果可以建模为不同的方法
    • 不要在方法内加断言
  • 字段意义
    • 不要暴露页面内部的元素给外部
    • 不需要建模UI内的所有元素

PO 改造流程

1、改造1:搭建起来PO 模式的架构,将业务逻辑先写出来,后面不需要改动,除非业务逻辑发生变化
2、改造2:填充业务逻辑,前端业务流程不变,只变后台逻辑
3、改造3:BasePage 封装,初始化driver
4、改造4:app.py 页面封装,复用driver , 判断 driver 是否为None, 如果 为None, 则创建一个driver, 否则 复用之前的driver , 使用 self.driver.launch_app() 启动app
5、改造5:BasePage 封装, find, find_and_click(), find_and_get_text,find_and_send_keys(), webdriverwait, gettoast_text …

练习

base_page.py

class BasePage:

    TOAST_TIPS = AppiumBy.XPATH, "//*[@class='android.widget.Toast']"

    def __init__(self, driver: WebDriver = None):
        """
        初始化driver
        :param driver:
        """
        self.driver = driver

    def find(self, by, value):
        """
        查找元素并返回
        :param by:
        :param value:
        :return:
        """
        return self.driver.find_element(by, value)

    def find_and_click(self, by, value):
        """
        查找元素并点击
        :param by:
        :param value:
        :return:
        """
        self.find(by, value).click()

    def find_and_send(self, by, value, text):
        """
        查找元素并输入
        :param by:
        :param value:
        :param text:
        :return:
        """
        self.find(by, value).send_keys(text)

    def set_implicitly_wait(self, time=1):
        """
        设置隐士等待
        :param time:
        :return:
        """
        self.driver.implicitly_wait(time)

    def get_toast_tips(self):
        """
        获取toast信息
        :return:
        """
        return self.find(*self.TOAST_TIPS).text

    def swipe_find(self, text, max_num=5):
        """
        滑动查找文本text
        :param text:
        :param max_num:
        :return:
        """
        self.set_implicitly_wait()
        # 滑动查找
        for num in range(max_num):
            try:
                element = self.driver.find_element(AppiumBy.XPATH, f"//*[@text='{text}']")
                sleep(1)
                return element
            except NoSuchElementException as e:
                print("未找到元素")
                # 获取屏幕大小
                size = self.driver.get_window_size()
                width = size.get("width")
                height = size.get("height")

                start_x = width / 2
                start_y = height * 0.8

                end_x = width / 2
                end_y = height * 0.2

                self.driver.swipe(start_x, start_y, end_x, end_y, 2000)
            if num == max_num - 1:
                self.set_implicitly_wait(10)
                # 执行最大次数,仍然没有找到文本,抛异常
                raise NoSuchElementException(f"找了{num}次,还是没有找到,请确认当前页面是否存在")

wework_app.py

class App(BasePage):

    def start(self):
        """
        启动app
        :return:
        """
        if self.driver == None:
            # 准备资源
            # 定义一个字典
            caps = {}
            # 被测手机的平台
            caps["platformName"] = "Android"
            caps["deviceName"] = "127.0.0.1:11509"
            # 包名和activity名称
            # adb logcat ActivityManager:I | findstr "cmp"
            # adb logcat ActivityManager:I | grep "cmp"
            caps["appPackage"] = "com.tencent.wework"
            caps["appActivity"] = ".launch.LaunchSplashActivity"
            # 防止清空缓存
            caps["noReset"] = "true"
            # 初始化driver
            self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
            # 设置隐士等待
            self.set_implicitly_wait(10)
        else:
            # 只启动当前测试的应用
            self.driver.launch_app()

    def restart(self):
        """
        重启
        :return:
        """
        pass

    def stop(self):
        """
        停止app
        :return:
        """
        pass

    def goto_main(self):
        """
        进入app首页
        :return:
        """
        return MainPage(self.driver)

main_page.py

class MainPage(BasePage):
    TAB_CONTACT = AppiumBy.XPATH, "//*[@text='通讯录']"

    def goto_contact_page(self):
        """
        进入通讯录界面
        :return:
        """
        self.find_and_click(*self.TAB_CONTACT)
        return ContactPage(self.driver)

contact_page.py

class ContactPage(BasePage):

    def goto_add_member_page(self):
        """
        进入添加成员界面
        :return:
        """
        self.swipe_find("添加成员").click()
        return AddMemberPage(self.driver)

add_member_page.py

class AddMemberPage(BasePage):
    TEXT_ADDMEMBER_MENUAL = AppiumBy.XPATH, "//*[@text='手动输入添加']"

    def goto_edit_contact_page(self):
        """
        进入到编辑成员界面
        :return:
        """
        self.find_and_click(*self.TEXT_ADDMEMBER_MENUAL)
        from page.edit_contact_page import EditContactPage
        return EditContactPage(self.driver)

edit_contact_page.py

class EditContactPage(BasePage):
    INPUT_NAME = AppiumBy.XPATH, "//*[@text='姓名 ']/../*[@text='必填']"
    INPUT_PHONE_NUMBER = AppiumBy.XPATH, "//*[@text='手机 ']/..//*[@text='必填']"
    BTN_SAVE = AppiumBy.XPATH, "//*[@text='保存']"

    def edit_member(self, name, phone_number):
        """
        输入姓名手机号,点击保存
        :param name:
        :param phone_number:
        :return:
        """
        # 输入【姓名】【手机号】
        self.find_and_send(*self.INPUT_NAME, name)
        self.find_and_send(*self.INPUT_PHONE_NUMBER, phone_number)
        # 点击【保存】
        self.find_and_click(*self.BTN_SAVE)
        from page.add_member_page import AddMemberPage
        return AddMemberPage(self.driver)

test_contact.py

class TestContact:

    def setup_class(self):
        # mocks数据
        self.faker = Faker("zh_CN")

    def setup(self):
        self.app = App()
        self.main_page = self.app.start().goto_main()

    def test_addcontact(self):
        """
        添加成员
        :return:
        """
        name = self.faker.name()
        phone_number = self.faker.phone_number()
        # 添加成员并获取tips值
        tips = self.main_page\
            .goto_contact_page()\
            .goto_add_member_page()\
            .goto_edit_contact_page()\
            .edit_member(name, phone_number)\
            .get_toast_tips()
        # 断言结果
        assert "添加成功" == tips

如果有两个人重名了,这个删除的用例会fail掉吧