本文为博主原创,未经许可严禁转载。
本文链接:https://blog.csdn.net/zyooooxie/article/details/113841107

2018年我开始在csdn写博客,最初就是在写UI自动化测试;
现如今2021年了,想着为了锻炼自己,写个app的自动化测试框架。

这是 App自动化测试的 category ,有兴趣 可以看看。

个人博客:https://blog.csdn.net/zyooooxie

需求

框架设计的目的:应用在冒烟测试、回归测试阶段;
脚本的用例:核心且稳定的业务;

要实现:

  1. 分层设计【po】;
  2. 用例执行失败时 重跑 + 断言失败、元素查找失败 自动截图 + 自定义用例执行的顺序;
  3. 截图、日志、测试报告的清理;
  4. 邮件提醒【Jenkins构建邮件 + 测试报告邮件】;
  5. 企微机器人提醒;

框架设计

使用: appium + pytest + allure + pytest-ordering + pytest-rerunfailures

  1. 清理本地文件(截图、日志);
  2. 卸载、再安装App;
  3. po 执行用例、 断言;Appium启动session,发送命令;
  4. 清理、重新生成测试报告;
  5. 发送(测试报告)邮件;企微通知;
  6. Jenkins定时构建;邮件通知Jobs构建情况;

具体实现

本系列分享 拿某Q极速版【安卓客户端】举例;

appPackage=csdn.zyooooxie.qqlite
appActivity=csdn.zyooooxie.mobileqq.activity.SplashActivity

本期主要讲述:

清理本地的 截图、日志文件

File:run_app.py


def delete_file():for i in [log_path, screen_ele_path, screen_assert_path]:os.chdir(i)all_file = os.listdir(i)if i == log_path:all_file.sort(key=os.path.getmtime, reverse=True)# 最新生成的日志 要保留all_file = all_file[1:]for f in all_file:os.remove(f)

卸载、安装App

File:apk_install.py


class ApkInstall(object):"""adb 命令来执行卸载、安装"""apk_path = app_pathdef __init__(self, package='csdn.zyooooxie.qqlite'):self.package = packagedef get_apk_name(self):os.chdir(self.apk_path)all_files = os.listdir(self.apk_path)apk = [a for a in all_files if a.endswith('apk')]apk_list = sorted(apk, key=lambda b: os.path.getctime(b), reverse=False)Log.info(apk_list[-1])return apk_list[-1]def uninstall_apk(self, first=None):# 不加-k  ('-k' means keep the data and cache directories)cmd = """adb uninstall {}""".format(self.package)r = os.popen(cmd)text = r.read()r.close()Log.info(cmd)if text.find('Failure') != -1:if first is not None:raise Exception('卸载报错')else:Log.info('未安装过,so 卸载失败')def install_apk(self, first_install=None, uninstall=None):apk = self.get_apk_name()if uninstall is not None:self.uninstall_apk(first=first_install)sleep(5)if first_install is None:cmd = """adb install -r {}""".format(apk)        # -r  (reinstall) 重装else:cmd = """adb install {}""".format(apk)Log.info(cmd)new_text = subprocess.check_output(cmd, shell=True)new_text = new_text.decode()print(new_text)sleep(5)if new_text.find('Success') != -1:Log.info('安装成功')else:raise Exception('安装有异常')

File:run_app.py


def install():ApkInstall('csdn.zyooooxie.qqlite').install_apk(first_install='yes', uninstall='yes')

appium启动session、退出

File:base_driver.py


class BaseDriver(object):def appium_desired(self, devices):desired_data = CommonFun.read_config(devices)desired_data = {d[0]: d[1] for d in desired_data}desired_caps = deepcopy(desired_data)desired_caps.update({'noReset': eval(desired_data['noReset'])})desired_caps.update({'unicodeKeyboard': eval(desired_data['unicodeKeyboard'])})desired_caps.update({'resetKeyboard': eval(desired_data['resetKeyboard'])})desired_caps.pop('ip')desired_caps.pop('port')u = "http://{}:{}/wd/hub".format(desired_data['ip'], desired_data['port'])driver = webdriver.Remote(u, desired_caps)return driverdef driver_quit(self, driver):# Sending command to android: {"cmd":"shutdown"} + driver.deleteSession() + kill all uiautomator processesdriver.quit()

po

File:base_method.py

class BaseMethod(object):"""基础方法"""def driver_find_element_and_wait(self, driver: WebDriver, by, location, the_time=10):"""等待元素可见:param driver::param by::param location::param the_time::return:"""if by not in MobileBy.__dict__.values() and by not in By.__dict__.values():raise NameError("Please enter the correct targeting elements.")try:ele = WebDriverWait(driver, the_time, poll_frequency=1).until(ec.visibility_of_element_located((by, location)))except Exception:Log.error('元素查找失败:{} '.format((by, location)))img_name = ''.join([time.strftime("%Y%m%d_%H%M%S"), '.png'])Log.info('已截图:{}'.format(img_name))driver.save_screenshot(os.path.join(screen_ele_path, img_name))raise NoSuchElementExceptionreturn eledef element_click(self, driver: WebDriver, by, location, the_time=10):self.driver_find_element_and_wait(driver, by, location, the_time).click()def element_send_keys(self, driver: WebDriver, keys, by, location, the_time=10):self.driver_find_element_and_wait(driver, by, location, the_time).clear().send_keys(keys)def assert_FindElement(self, driver: WebDriver, by, location, the_time=10):try:WebDriverWait(driver, the_time).until(ec.visibility_of_element_located((by, location)), '查找失败')# TimeoutExceptionexcept Exception as e:Log.debug(repr(e))Log.error('断言时 元素找不到:{}'.format((by, location)))img_name = ''.join([time.strftime("%Y%m%d_%H%M%S"), '.png'])Log.info('已截图:{}'.format(img_name))driver.save_screenshot(os.path.join(screen_assert_path, img_name))raise AssertionErrordef assert_app(self, driver: WebDriver, app_name):print(driver.current_activity, driver.current_package)assert driver.current_activity != app_name

File:page_test.py

class PageTest(BaseMethod):# 暂不使用not_in_use = (By.ID, 'csdn.zyooooxie.qqlite:id/dialogLeftBtn')# 同意in_use = (By.ID, 'csdn.zyooooxie.qqlite:id/dialogRightBtn')in_use2 = (MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("同意")')in_use3 = (MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().description("同意")')in_use4 = (MobileBy.ACCESSIBILITY_ID, '同意')in_use5 = (MobileBy.ID, 'dialogRightBtn')# 服务协议service_agreement = (By.ID, 'csdn.zyooooxie.qqlite:id/dialogText')login = (By.ID, 'csdn.zyooooxie.qqlite:id/btn_login')# 完全不存在fail = (By.ID, 'csdn.zyooooxie.qqlite:id/fail')# 选择 暂不使用def choose_NotInUse(self, driver: WebDriver):self.driver_find_element_and_wait(driver, *self.not_in_use).click()sleep(2)# 点击 服务协议def click_Service(self, driver: WebDriver):self.driver_find_element_and_wait(driver, *self.service_agreement).click()sleep(2)

File:test_test.py


@pytest.mark.first
@allure.feature('测试TEST')
class TestTest(PageTest):@allure.story('暂不使用')@allure.title('用例1')@mark_smokedef test_0(self, driver):allure.dynamic.description("动态description0")self.choose_NotInUse(driver)time.sleep(1)self.assert_app(driver, CommonFun.read_config('phone_honor', option='appPackage'))@allure.story('服务协议')@allure.title('用例2')def test_1(self, driver):allure.dynamic.description("动态description1")self.click_Service(driver)self.assert_FindElement(driver, *self.not_in_use)# @pytest.mark.run(order=14)@allure.story('同意')@allure.title('用例1')def test_2a(self, driver):allure.dynamic.description("动态description2")print(self.driver_find_element_and_wait(driver, *self.in_use).text)self.assert_FindElement(driver, *self.not_in_use)@allure.story('同意')@allure.title('用例2')def test_2b(self, driver):allure.dynamic.description("动态description3")print(self.driver_find_element_and_wait(driver, *self.in_use2).text)self.assert_FindElement(driver, *self.not_in_use)@pytest.mark.skip(reason='跳过')@allure.story('同意')@allure.title('用例3')def test_2c(self, driver):allure.dynamic.description("动态description4")print(self.driver_find_element_and_wait(driver, *self.in_use3).text)self.assert_FindElement(driver, *self.not_in_use)@allure.story('同意')@allure.title('用例4')def test_2d(self, driver):allure.dynamic.description("动态description5")print(self.driver_find_element_and_wait(driver, *self.in_use4).text)# 断言失败self.assert_FindElement(driver, *self.fail)@allure.story('同意')@allure.title('用例5')def test_3(self, driver):allure.dynamic.description("动态description6")self.driver_find_element_and_wait(driver, *self.in_use5).click()self.assert_FindElement(driver, *self.login)@allure.story('同意')@pytest.mark.run(order=13)@allure.title('用例6')def test_4(self, driver):allure.dynamic.description("动态description7")print(driver.current_activity)@allure.story('失败')@allure.title('用例1')def test_5(self, driver):allure.dynamic.description("动态description8")# 查找元素失败self.driver_find_element_and_wait(driver, *self.fail).click()self.assert_FindElement(driver, *self.fail)@pytest.mark.skip@allure.story('跳过')@allure.title('用例0')def test_6(self, driver):allure.dynamic.description("动态description9")print(driver.current_activity)@skip_mark@allure.story('跳过')@allure.title('用例1')def test_7a(self, driver):allure.dynamic.description("动态description10")print(driver.current_activity)@skip_mark@allure.story('跳过')@allure.title('用例2')def test_7b(self, driver):allure.dynamic.description("动态description")print(driver.current_activity)

File:conftest.py

@pytest.fixture(scope='function')
def driver():b = BaseDriver()device = 'phone_honor'dr = b.appium_desired(devices=device)yield drb.driver_quit(dr)

结果展示

这一篇主要的内容就这些;

本系列 第二篇 生成测试报告,邮件、企微通知+Jenkins构建通知

交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie

Appium App自动化测试框架【一】相关推荐

  1. APP自动化测试框架搭建(五)--Python+Appium+pytest-html

    第一章 APP自动化环境搭建(Mac版) 第二章 APP自动化环境搭建(Windows版) 第三章 adb命令 第四章 元素定位.元素操作 第五章 APP自动化测试框架搭建 Python+Appium ...

  2. python app自动化测试框架_appium+python,app自动化测试框架

    基于appium的app自动化测试框架 基于appium框架的app自动化测试 App自动化测试主要难点在于环境的搭建,appium完全是基于selenium进行的扩展,所以app测试框架也是基于we ...

  3. APP自动化测试框架搭建(八)--ATX Server2多设备集群环境搭建

    第一章 APP自动化环境搭建(Mac版) 第二章 APP自动化环境搭建(Windows版) 第三章 adb命令 第四章 元素定位.元素操作 第五章 APP自动化测试框架搭建 Python+Appium ...

  4. APP自动化测试框架

    目前常见的APP自动化测试框架有以下几类: 1. Instrumentation Instrumentation,早期Google提供的Android自动化测试工具类.它和Activity有点类似,但 ...

  5. APP自动化测试框架搭建(六)--uiautomator2、web-editor基础操作

    第一章 APP自动化环境搭建(Mac版) 第二章 APP自动化环境搭建(Windows版) 第三章 adb命令 第四章 元素定位.元素操作 第五章 APP自动化测试框架搭建 Python+Appium ...

  6. 视频教程-Appium移动自动化测试框架-软件测试

    Appium移动自动化测试框架 河北师大软件学院测试教室主任.项目基地测试经理;尚大学.金牌讲师.擅长技术: 项目模块化流程设计.软件测试流程设计及优化.项目管理平台的整合与应用.功能性自动化测试工具 ...

  7. uiautomator2,一款比appium还好用的app自动化测试框架

    一说到app自动化测试,第一反应就会想到appium这个框架,和web端的selenium一样,但是对于appium来说,搭建环境非常重要,很多人都被环境搞得望而却步了,放弃了appium. 下面说的 ...

  8. android app自动化测试框架Appium资料整理

    by Ruiming.Lv 1   自动化测试 1.1    自动化测试简介 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程.从广义上来讲,一切通过工具(程序)的方式来代替或辅助手工测试的 ...

  9. 如何搭建App自动化测试框架?

    目录 前言 安装Java JDK 安装Node.js 安装Appium server 第一种:使用npm工具 第二种:安装desktop版本 配置环境变量 安装Android SDK 下载SDK及安装 ...

最新文章

  1. (完全解决)ValueError: Invalid RGBA argument: 0.2
  2. laravel mysql 锁表_Laravel 数据库加密及数据库表前缀配置方法
  3. vscode如何用浏览器预览运行html文件
  4. Spring(2)——Spring IoC 详解
  5. 每日一题(22)——malloc与free(三)
  6. c++ int自动转换成无符号变量产生的问题
  7. 容器编排技术 -- Kubernetes kubectl create service externalname 命令详解
  8. 字符串比较strcmp
  9. 静态html如何写入文件,静态HTML模板渲染
  10. Homebrew 更换阿里云镜像源
  11. 2021年四川省副高考试成绩查询,2021年四川省教育考试院成绩查询登录入口
  12. java实现打印功能_Js 打印功能的实现(Java)
  13. 圣杯布局(三栏布局)
  14. 用jsp代码完成购物车并且实现添加功能
  15. 计算机控制面板 关机时间,怎么设置电脑的自动关机时间
  16. 中国移动短信网关错误代码汇总(完整版)
  17. 股票的内外盘(转贴收藏)
  18. 如何调整MATLAB画布大小?
  19. java 秒表暂停_java – 停止秒表
  20. 理性拥抱机器学习热潮:ML祖师爷Tom Mitchell最新洞见

热门文章

  1. 关于信息化、数字化、数据化……等的区别!
  2. 如何用百数低代码开发平台实现会议预约?
  3. 计算机课故事作文,有趣的电脑课日记600字
  4. 音视频直播如何实现低延迟
  5. Word文档中如何快速切换英文大小写?掌握这个方法轻松完成
  6. (转)WORD中小写金额转换成大写
  7. 分享:Vue.js新手入门指南-0518-v1.0张雅慧
  8. 野火STM32F407-霸天虎DSP库移植
  9. pkgsearch搜索和查询CRAN R包_2021-01-26
  10. python求平衡点的几种方法