首页/新闻资讯/正文详情

python-for-android 真机单元测试应用(On Device Unit Tests)完全指南:构建、运行与结果验证

发布时间:2026/9/25 4:04:08 来源:云帆数科 栏目:资讯中心
python-for-android 真机单元测试应用(On Device Unit Tests)完全指南:构建、运行与结果验证
开发工具构建工具移动开发【免费下载链接】python-for-androidTurn your Python application into an Android APK项目地址https://gitcode.com/gh_mirrors/py/python-for-android点击查看免费下载导读本文围绕 python-for-android 仓库中testapps/on_device_unit_tests/目录下的专用测试应用展开讲解如何使用它验证 python-for-android 构建出的 APK 中各个 recipe配方是否真正可用。读完本文你将掌握三种应用模式kivy / flask / 无 GUI的触发条件、通过setup.py与 buildozer 两条路径构建测试应用的完整流程以及通过adb logcat在真机上核对单元测试结果的方法并理解该动态测试应用背后的源码级工作机制。一、这个测试应用是什么testapps/on_device_unit_tests/下的测试应用是一套跑在 Android 设备上的单元测试集其设计目的是帮助确认 python-for-android 构建出的 APK 内部真的能正常工作——即不止于打包成功而是 APK 里被编入的各个 Python 模块能够被导入、执行基本操作见 README.rst。它的核心特点在于动态性dynamic同一个应用会根据构建时传入的requirementsrecipe 列表自动决定两件事运行哪套测试requirements中出现哪个 recipe就去运行对应的TestCase采用哪种界面形态是 Kivy GUI、Flask Web 界面还是纯终端输出。应用当前支持三种mode由构建时的requirements内容触发模式触发条件对应的 bootstrapkivy apprequirements中包含kivysdl2flask apprequirements中包含flaskwebviewno gui以上两者都不存在终端直接跑 unittest从源码看main.py判定顺序是kivy in requirements→ 启动TestKivyApp否则flask in requirements→ 启动app_flask两者都不是 → 用unittest.TextTestRunner()在终端直接运行测试套件。测试应用的主要测试对象是APK 中构建出来的各个 recipe。每个模块或其他工具至少会被导入一次并接受一项基础功能检查Each module (or other tool) is at least imported and subject to some basic check。测试用例全部定义在 test_app/tests/test_requirements.py 中。二、动态测试的源码机制requirements 如何决定测试集理解动态二字需要看 test_app/main.py 的启动逻辑它是整个测试应用的调度中心# 读取 app_requirements.txt 并确定要执行的测试 requirements None if isfile(app_requirements.txt): with open(app_requirements.txt, r) as requirements_file: requirements set(requirements_file.read().splitlines()) if not requirements: # 缺省测试一组基础 recipe requirements {sqlite3, libffi, openssl, pyjnius} for recipe in requirements: test_name tests.test_requirements.{recipe}TestCase.format( reciperecipe.capitalize() ) ...关键链路如下约定文件app_requirements.txt应用启动时首先在当前目录查找该文件。文件里每一行是一个 recipe 名构建时由setup.py自动生成生成逻辑见 setup.py它会把requirements逐个写入该文件并去掉版本号。命名约定每个测试类命名为tests.test_requirements.RecipeTestCaserecipe 名首字母大写例如sqlite3→Sqlite3TestCase。main.py 按此规则为每个 recipe 动态拼接类名通过unittest.TestLoader().loadTestsFromName()尝试加载加载失败说明该 recipe 没有对应测试会被静默跳过。找不到文件时的回退若app_requirements.txt不存在例如直接用 buildozer 构建时该文件不会生成则默认测试{sqlite3, libffi, openssl, pyjnius}这一组基础 recipe。界面分流确定tests_to_perform之后再按上文表格分流到 Kivy / Flask / 终端三种运行方式。值得注意main.py 的 docstring 明确指出这个应用同时在桌面和 Android 设备上可运行但部分功能如 pyjnius 触发的震动、Activity 生命周期回调只在真机上生效。这一点在tools.py中由RUNNING_ON_ANDROID检测环境变量ANDROID_APP_PATH是否存在见 constants.py配合skip_if_not_running_from_android_device装饰器控制。三、测试用例一览每个 recipe 测什么所有测试类都继承自PythonTestMixInmixin.py该 MixIn 提供了两个基础方法test_import_module通过importlib.import_module(self.module_import)验证模块能被导入公共测试所有子类自动继承test_run_module导入后做一次最小化的功能验证默认直接self.fail()要求每个子类必须重写。下面列出 test_requirements.py 中现有测试类及其验证点可作为你为自定义 recipe 编写真机测试的模板参考测试类对应 recipe导入模块最小功能验证NumpyTestCasenumpynumpy生成 3×3 随机矩阵并计算行列式ScipyTestCasescipyscipywhiten/kmeans/vq聚类基本操作OpensslTestCaseopenssl_sslssl.create_default_context()并调整选项Sqlite3TestCasesqlite3sqlite3连接example.db并创建 cursorKivyTestCasekivykivy导入kivy.core.window.Window有副作用能导入即说明 Kivy 正常PyjniusTestCasepyjniusjniusautoclass(org.kivy.android.PythonActivity)LibffiTestCaselibffictypes在 Android 上cdll.LoadLibrary(libc.so)并调用printfGreenletTestCasegreenletgreenlet._greenlet协程switch(41) 42且worker.deadRequestsTestCaserequestsrequests真实发起GET https://kivy.org/请求PillowTestCasePillowPIL打开static/colours.png缩放、画框、高斯模糊、文字合成并保存 PNGMatplotlibTestCasematplotlibmatplotlib绘图、加图例、保存matplotlib_test.pngCryptographyTestCasecryptographycryptographyFernet 加解密往返PycryptoTestCasepycryptoCryptoSHA256哈希PycryptodomeTestCasepycryptodomeCrypto生成 2048 位 RSA 密钥并导出ScryptTestCasescryptscryptscrypt.hash输出长度必须为 64 字节M2CryptoTestCasem2cryptoM2Crypto创建SSL.Context(sslv23)Pysha3TestCasepysha3sha3keccak_512()哈希LibtorrentTestCaselibtorrentlibtorrent打印lt.versionPyside6TestCasePySide6PySide6导入 QtCore / QtWidgets 并取当前时间Shiboken6TestCaseshiboken6shiboken6打印版本号其中PillowTestCase与MatplotlibTestCase会在应用根目录生成 PNG 图片Kivy 模式下的应用会通过get_images_with_extension()tools.py检测这些图片并在 UI 中展示方便肉眼核对测试产物。四、使用 python-for-android 构建测试应用setup.py 路径仓库为测试应用提供了专用的 setup.py其内部通过setuptools的options字典直接对接 python-for-android 的构建参数。默认配置是一个 Kivy 基础应用项目文档注释说明python-for-android 是 Kivy 的姊妹项目因此默认以 Kivy 应用为准options { apk: { requirements: sqlite3,libffi,openssl,pyjnius,kivy,python3,requests,urllib3, chardet,idna, android-api: 36, ndk-api: 24, dist-name: bdist_unit_tests_app, arch: armeabi-v7a, bootstrap: sdl2, permissions: [INTERNET, VIBRATE], orientation: [portrait, landscape], service: P4a_test_service:app_service.py, }, ... }setup.py 同时定义了apk、aab、aar三套构建目标aab与apk配置一致sdl2 bootstrap而aar使用service_librarybootstrap、arch: arm64-v8a、仅requirements: python3用于验证以库Android Archive形式输出的构建。4.1 通过命令行覆盖 requirementssetup.py 支持在命令行中用--requirements参数覆盖默认的测试 recipe 集合requirements options[apk][requirements].rsplit(,) for n, arg in enumerate(sys.argv): if arg --requirements: print(found requirements) requirements sys.argv[n 1].rsplit(,) break需要强调的是requirements参数是决定测试集的关键。文档注释明确指出你想测试哪个 recipe就必须显式把它写进requirements并且该 recipe 必须已在tests/test_requirements.py中存在对应的TestCase否则nothing will be tested什么都测不到。4.2 三种模式的推荐 requirements 示例setup.py 的 docstring 给出了三种受支持模式的推荐组合这是原文档的核心实操内容直接继承kivy 基础版sqlite3,libffi,openssl,pyjnius,kivy,python3,requests,urllib3,chardet,idnakivy 图像/绘图版kivy,python3,numpy,matplotlib,Pillowkivy 加密版kivy,python3,cryptography,pycryptodome,scrypt,m2crypto,pysha3flaskwebview bootstrapsqlite3,libffi,openssl,pyjnius,flask,python3,genericndkbuild两个值得注意的细节源码注释中明确说明在kivy basic组合中特意加入sqlite3,libffi,openssl是为了触发这三个 recipe 对应的单元测试想在不显式传bootstrap参数的情况下让 python-for-android 生成 flask 应用可以加入genericndkbuild这个 recipe它会在构建时触发 webview bootstrap见 setup.py 的 docstring。4.3 构建前的自动处理逻辑setup.py 在调用setup()之前还做了两件关键事移除不支持的参数当requirements中既没有kivy也没有flask即走 no-gui / service 模式时会options[apk].pop(orientation)——因为service_onlybootstrap 不支持orientation参数setup.py。生成app_requirements.txt把最终确定的 requirements 逐行写入test_app/app_requirements.txt供应用启动时读取前文已述。构建命令的完整形态需要参考仓库 Makefile 中测试应用相关的 target以及 ci/run_emulator_tests.sh 等 CI 脚本中的实际调用方式这些脚本是怎么用 setup.py 构建这个测试应用最直接的现成范例。五、使用 buildozer 构建测试应用除了 setup.py 路径测试应用同样可以用buildozer构建而这条路径本身也是对 buildozer 集成 python-for-android 能力的一项测试。仓库为该目录提供了完整的 buildozer.spec核心配置如下[app] title p4a unit tests package.name p4aunittests package.domain org.kivy source.dir test_app source.include_exts py,png,jpg,kv,atlas,html,css,otf,txt version 0.1 requirements python3,kivy,libffi,openssl,numpy,sqlite3 orientation all android.api 35 android.arch armeabi-v7a android.whitelist unittest/* p4a.branch develop几点说明source.dir test_app指向测试应用源码目录requirements与 setup.py 默认值略有差异这里为python3,kivy,libffi,openssl,numpy,sqlite3同样遵循想测什么就写什么的原则android.whitelist unittest/*用于把 Python 标准库unittest相关文件保留进 APK避免被 python-for-android 的裁剪机制剔除p4a.branch develop指定使用 python-for-android 的 develop 分支当前仓库即该分支的镜像。使用 buildozer 构建的命令原文档核心命令原样继承$ buildozer android debug需要注意的局限main.py 的 docstring 中有明确 warning如果使用 buildozer 构建只会得到基础的 kivy unittest 应用且测试集是基础集合sqlite3、libffi、openssl 和 pyjnius。原因是 buildozer 构建时不会生成app_requirements.txtmain.py 会回退到默认测试集。若需要自定义测试集应使用 setup.py 路径它会自动生成该文件或在构建产物中手动补建app_requirements.txt。六、安装到设备与运行构建产物是一个 APKbuildozer 输出在bin/目录文件名为p4aunittests-0.1-debug.apk对应 spec 中的version 0.1与package.name p4aunittests。安装与运行的原文档命令如下方式一adb 直接安装注意原文档中该命令形如adb install -r adb install -r ...实际正确的单次安装命令为$ adb install -r bin/p4aunittests-0.1-debug.apk方式二buildozer 部署$ buildozer android deploy安装完成后启动应用即可在设备上运行单元测试。七、查看测试结果logcat 与界面反馈测试结果有两种查看途径取决于应用模式7.1 终端输出模式no-gui如果你构建的是no-gui 测试应用unittest 结果不会显示在屏幕上必须通过以下命令从系统日志中查看$ adb logcat | grep python # 或查阅你所用 adb 版本的过滤语法原文档特别提醒也可以使用某些日志查看 APK 来观察输出但这类工具在设备上可能需要 root 权限you may need root permissions in your device to use such app。7.2 GUI 模式kivy / flaskKivy 模式应用启动后自动进入ScreenUnittests界面由 screen_unittests.kv 定义并通过 app_kivy.py 中run_unittests()在启动 3 秒后Clock.schedule_once(self.run_unittests, 3)执行测试。结果反馈非常直观每个被测 recipe 以彩色文本呈现灰色 测试开始前待运行、红色 该 recipe 的测试失败、绿色 通过颜色逻辑见set_color_for_tested_modules()对应#838383/#ff0000/#5d8000测试生成的 PNG 图片如 Pillow / Matplotlib 用例的产物会以缩略图形式展示在test_images_box中界面上还附带键盘、屏幕方向切换、震动pyjnius 调 Android Vibrator、服务启停P4a_test_service等辅助测试功能分别由screen_keyboard.kv、screen_orientation.kv、screen_service.kv提供入口。Flask 模式启动后通过浏览器访问http://设备IP:5000//unittests路由app_flask.py会执行测试套件并把结果渲染成带红/绿颜色的 HTML 页面。该模式下 Flask 以非线程方式运行app.run(threadedFalse, ...)这是因为 pyjnius 在请求处理器里解析应用类时新原生线程会使用 Java 系统类加载器导致 JNI 失败源码注释引用了 python-for-android issue #2533。7.3 日志中该看什么无论哪种模式unittest.TextTestRunner的输出通过run_test_suites_into_buffer()捕获见 tools.py都会包含标准的结果摘要例如各测试类名、OK/FAILED标记与失败明细。在 logcat 中过滤python标签即可看到这些内容Kivy / Flask 模式下应用也会用print()输出 Imported unittest、running unittest... 等阶段性日志如 main.py 的print(Imported unittest)可用于确认测试是否被真正触发。八、桌面端调试技巧与扩展测试main.py 的 docstring 提供了一条对开发者非常实用的桌面调试路径应用同时支持在桌面运行前提是本地已安装相应 Python 包如 kivy、flask你可以直接在test_app/app_requirements.txt里手工编辑 recipe 列表每行一个注意 recipe 名的大小写必须与测试类名对应从而在桌面上快速跑一遍测试、不必每次重新构建 APK但要注意app_requirements.txt是setup.py运行时的自动生成文件在某些情况下可能需要你手动创建它例如直接用 buildozer 构建时。扩展新测试的规范流程是先在 tests/test_requirements.py 中仿照现有类新增XxxTestCase(PythonTestMixIn, TestCase)设置module_import并重写test_run_module然后在构建时把对应 recipe 加入requirements——测试就会自动被动态调度器发现并执行。九、CI 中的实际应用该测试应用并非孤立示例它已被集成到项目的 CI 流程中。仓库 ci/run_emulator_tests.sh 与 ci/rebuild_updated_recipes.py 等脚本承担了构建测试应用 → 启动 Android 模拟器 → 安装 APK → 抓取 logcat 验证测试结果的自动化职责其具体做法构建参数、过滤关键字、结果判定逻辑可以作为在本地复现整套真机验证流程的参考蓝本——这也解释了为什么本文开头强调这个测试应用的目标是帮助确认 python-for-android 的构建实际可用而不只是能打包。十、小结testapps/on_device_unit_tests/是一个围绕 python-for-android 构建产物设计的动态真机测试应用它以requirements为输入通过app_requirements.txttests/test_requirements.py的命名约定动态组装测试集再按kivy/flask/ 无 GUI 三种模式分别呈现结果。构建路径有 setup.py可自定义测试集、生成app_requirements.txt与 buildozer固定基础测试集两条结果核对在无 GUI 模式下依赖adb logcat | grep python在 GUI 模式下则有界面上的红/绿状态与生成图片反馈。理解这套机制后你可以轻松复用它来验证任何新增 recipe 在真实 Android 设备上的可用性。赞分享开发工具构建工具移动开发【免费下载链接】python-for-androidTurn your Python application into an Android APK项目地址https://gitcode.com/gh_mirrors/py/python-for-android点击查看免费下载相关推荐curl 单元测试完全指南构建、运行、调试与编写 libcurl 单测tests/unit 详解curl 单元测试完全指南构建、运行、调试与编写 libcurl 单测tests/unit 详解 curl 仓库在 tests/unit/ 目录下维护了一CLI网络通信Flipper Zero 固件单元测试完全指南在设备端运行与编写 Unit TestsFlipper Zero 固件单元测试完全指南在设备端运行与编写 Unit Tests 本文基于 documentation/UnitTests.md htt文档教程gRPC Python 测试凭据体系全解tests/unit/credentials 证书层次结构与 TLS 测试应用gRPC Python 测试凭据体系全解 tests/unit/credentials 证书层次结构与 TLS 测试应用 导读 本文深入剖析 gRPC Pyt后端RPC框架微服务通信上一篇Scrapling 完全指南自适应 Web Scraping 框架的 Fetcher、Spider 与 CLI 全解析下一篇深入解析LLVM中的JIT编译技术实时优化与执行的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

工业AI Agent落地实战:从良率异常分析到智能体架构拆解
工业AI Agent落地实战:从良率异常分析到智能体架构拆解

1. 工厂里的AI Agent到底在干什么1.1 从一条产线异常说起去年冬天,我在一家做精密结构件的工厂里蹲了三天。产线上一台注塑机的良率突然从98.6%掉到94%出头,班组长第一反应是"原料批次有问题",换了料还是不行;第二反应是… · 2026/9/25 4:04:02

AI4AI实战:用EvoX和EvoMap自动进化优化Agent系统
AI4AI实战:用EvoX和EvoMap自动进化优化Agent系统

1. 从一条热搜说起:AI4AI 到底在做什么第一次看到 EvoX 和 EvoMap 这两个词出现在热搜榜上的时候,我正蹲在一个 Agent 项目的调试现场,满屏的agent execution terminated due to error刷得人头皮发麻。当时第一反应是:又来了一个新… · 2026/9/25 4:04:02

嵌入式WASM开发:ESP32上硬件访问的边界与正确姿势
嵌入式WASM开发:ESP32上硬件访问的边界与正确姿势

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:03:50

Ariakit Component Stores:高性能组件状态管理的读写机制与源码解析
Ariakit Component Stores:高性能组件状态管理的读写机制与源码解析

UI组件前端 【免费下载链接】ariakit Toolkit with accessible components, styles, and examples for your next web app 项目地址: https://gitcode.com/gh_mirrors/ar/ariakit 点击查看 免费下载 Component stores 是 Ariakit 提供的底层状态管理层:… · 2026/9/25 4:32:17

AI芯片选型全解析:核心参数、软件生态与实战避坑指南
AI芯片选型全解析:核心参数、软件生态与实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:32:17

证书吊销的实时性治理:安当CAS 在车规场景的落地实践
证书吊销的实时性治理:安当CAS 在车规场景的落地实践

一、引言:车规证书吊销为什么是"生死线" 在传统 IT 领域,一张证书泄露后即便没被及时吊销,攻击者能做的事情往往限于窃听或伪装某个 Web 站点;但在汽车电子里,证书的用途被直接绑定到车辆的"执行权&quo… · 2026/9/25 4:32:04

脱敏规则的版本管理与灰度发布实践:安当DBG 在数据库脱敏策略治理中的落地
脱敏规则的版本管理与灰度发布实践:安当DBG 在数据库脱敏策略治理中的落地

一、为什么脱敏规则也需要"版本管理" 在数据库动态脱敏的落地中,技术团队往往把重心放在"能不能脱敏"上,而忽略了"规则改错了怎么办"。但事实上,脱敏规则本身是一份会持续演进的策略文件:新业务上线… · 2026/9/25 4:32:04

LT9611 MIPI转HDMI移植实战:设备树配置与调试全解析
LT9611 MIPI转HDMI移植实战:设备树配置与调试全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:32:04

STM32F103ZET6板卡调试:从原理图分析到GPIO代码实战
STM32F103ZET6板卡调试:从原理图分析到GPIO代码实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:31:58

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码