Files
Android-pyApi/android_pyapi/android/test.py
T
shuiyu1123 506f9ac725 feat: 新增 42 个 Android API 模块
新增模块覆盖:
系统层 (14): system, security, print, opengl, renderscript, transition,
test, service_notification, service_controls, service_quicksettings,
service_wallpaper, service_autofill, service_dreams, service_vr

应用层 (13): app_admin, app_backup, app_job, app_usage, app_role,
app_people, appwidget, companion, credentials, mtp, sip, telecom, speech

硬件媒体层 (15): hardware_display, hardware_fingerprint, hardware_usb,
hardware_input, media_audiofx, media_browse, media_session, media_tv,
media_midi, media_projection, uwb, se, view_autofill, view_textclassifier,
view_translation

总计 94 个模块,75,342 行代码
2026-06-24 12:00:28 +00:00

485 lines
16 KiB
Python

"""
Android Test 组件 — InstrumentationTestRunner, InstrumentationTestCase,
ActivityInstrumentationTestCase2, ActivityUnitTestCase, ServiceTestCase,
ProviderTestCase2, ApplicationTestCase, Instrumentation 等
方法签名完全对齐 Android SDK (android.test 包)
"""
import os
import sys
import time
import threading
from typing import Any, Callable, Dict, List, Optional, Tuple, Type
from .._core import Stub, AndroidOnlyError
# ═══════════════════════════════════════════════════════════════
# Instrumentation
# ═══════════════════════════════════════════════════════════════
class Instrumentation(Stub):
"""Instrumentation — 测试仪器 (桌面版)"""
# 报告标志
REPORT_KEY_IDENTIFIER = "id"
REPORT_KEY_STREAM_RESULTS = "stream"
def __init__(self):
super().__init__()
self._context: Optional[Any] = None
self._target_context: Optional[Any] = None
self._started = False
self._finished = False
self._automatic_performance_snapshots = False
self._instr_result: Dict[str, Any] = {}
def onCreate(self, arguments: Any):
"""创建仪器"""
self._started = True
def onStart(self):
"""启动仪器"""
pass
def onDestroy(self):
"""销毁仪器"""
self._finished = True
def getContext(self) -> Optional[Any]:
"""获取上下文"""
return self._context
def getTargetContext(self) -> Optional[Any]:
"""获取目标上下文"""
return self._target_context
def setContext(self, context: Any):
self._context = context
def setTargetContext(self, target_context: Any):
self._target_context = target_context
def startActivitySync(self, intent: Any) -> Any:
"""同步启动 Activity"""
return None
def sendKeySync(self, key_event: Any):
"""发送按键事件"""
pass
def sendCharacterSync(self, character: int):
"""发送字符事件"""
pass
def sendStringSync(self, text: str):
"""发送字符串"""
pass
def sendPointerSync(self, motion_event: Any):
"""发送指针事件"""
pass
def sendTrackballEventSync(self, motion_event: Any):
"""发送轨迹球事件"""
pass
def runOnMainSync(self, runner: Callable):
"""在主线程上同步运行"""
runner()
def waitForIdle(self):
"""等待空闲"""
pass
def waitForIdleSync(self):
"""同步等待空闲"""
pass
def callActivityOnCreate(self, activity: Any, icicle: Any):
"""调用 Activity.onCreate"""
if hasattr(activity, 'onCreate'):
activity.onCreate(icicle)
def callActivityOnStart(self, activity: Any):
"""调用 Activity.onStart"""
if hasattr(activity, 'onStart'):
activity.onStart()
def callActivityOnResume(self, activity: Any):
"""调用 Activity.onResume"""
if hasattr(activity, 'onResume'):
activity.onResume()
def callActivityOnPause(self, activity: Any):
"""调用 Activity.onPause"""
if hasattr(activity, 'onPause'):
activity.onPause()
def callActivityOnStop(self, activity: Any):
"""调用 Activity.onStop"""
if hasattr(activity, 'onStop'):
activity.onStop()
def callActivityOnDestroy(self, activity: Any):
"""调用 Activity.onDestroy"""
if hasattr(activity, 'onDestroy'):
activity.onDestroy()
def callActivityOnRestart(self, activity: Any):
"""调用 Activity.onRestart"""
if hasattr(activity, 'onRestart'):
activity.onRestart()
def isProfiling(self) -> bool:
return False
def startProfiling(self):
pass
def stopProfiling(self):
pass
def setInTouchMode(self, in_touch: bool):
pass
def finish(self, result_code: int, results: Any = None):
"""完成测试"""
self._finished = True
if results:
self._instr_result.update(results)
def getComponentName(self) -> Any:
return None
def getUiAutomation(self) -> Any:
return None
def toString(self) -> str:
return (f"Instrumentation(started={self._started}, "
f"finished={self._finished})")
def hashCode(self) -> int:
return id(self) & 0x7FFFFFFF
def equals(self, other) -> bool:
return self is other
# ═══════════════════════════════════════════════════════════════
# InstrumentationTestRunner
# ═══════════════════════════════════════════════════════════════
class InstrumentationTestRunner(Stub):
"""InstrumentationTestRunner — 仪器化测试运行器"""
REPORT_KEY_NAME = "name"
REPORT_KEY_CLASS = "class"
REPORT_KEY_TEST = "test"
REPORT_KEY_NUM_TOTAL = "numtests"
REPORT_KEY_NUM_CURRENT = "current"
REPORT_KEY_NUM_ITERATIONS = "numiterations"
def __init__(self):
super().__init__()
self._instrumentation = Instrumentation()
self._test_results: List[Dict[str, Any]] = []
def onCreate(self, arguments: Any):
"""创建测试运行器"""
self._instrumentation.onCreate(arguments)
def onStart(self):
"""开始测试"""
self._instrumentation.onStart()
def onDestroy(self):
"""销毁"""
self._instrumentation.onDestroy()
def getInstrumentation(self) -> Instrumentation:
return self._instrumentation
def runTest(self, test_case: Any):
"""运行测试用例"""
try:
if hasattr(test_case, 'setUp'):
test_case.setUp()
if hasattr(test_case, 'runTest'):
test_case.runTest()
if hasattr(test_case, 'tearDown'):
test_case.tearDown()
self._test_results.append({"success": True, "test": str(test_case)})
except Exception as e:
self._test_results.append({
"success": False, "test": str(test_case), "error": str(e),
})
def getTestResults(self) -> List[Dict[str, Any]]:
return list(self._test_results)
def toString(self) -> str:
return (f"InstrumentationTestRunner("
f"results={len(self._test_results)})")
def hashCode(self) -> int:
return id(self) & 0x7FFFFFFF
def equals(self, other) -> bool:
return self is other
# ═══════════════════════════════════════════════════════════════
# InstrumentationTestCase
# ═══════════════════════════════════════════════════════════════
class InstrumentationTestCase(Stub):
"""InstrumentationTestCase — 仪器化测试用例基类"""
def __init__(self):
super().__init__()
self._instrumentation: Optional[Instrumentation] = None
self._test_name: str = ""
def injectInstrumentation(self, instrumentation: Instrumentation):
"""注入仪器"""
self._instrumentation = instrumentation
def getInstrumentation(self) -> Optional[Instrumentation]:
return self._instrumentation
def setUp(self):
"""测试前准备"""
pass
def tearDown(self):
"""测试后清理"""
pass
def runTest(self):
"""执行测试"""
pass
def sendKeys(self, *keys: str):
"""发送按键"""
pass
def touchDown(self, view: Any, x: float, y: float):
"""触摸按下"""
pass
def touchUp(self, view: Any, x: float, y: float):
"""触摸抬起"""
pass
def touchAndHold(self, view: Any, x: float, y: float):
"""触摸并按住"""
pass
def click(self, view: Any):
"""点击"""
pass
def typeText(self, view: Any, text: str):
"""输入文本"""
pass
def assertActivityRequiresFeature(self, activity_class: Any,
feature: str) -> bool:
return True
def toString(self) -> str:
return f"InstrumentationTestCase(name={self._test_name})"
def hashCode(self) -> int:
return hash(self._test_name) & 0x7FFFFFFF
def equals(self, other) -> bool:
if not isinstance(other, InstrumentationTestCase):
return False
return self._test_name == other._test_name
# ═══════════════════════════════════════════════════════════════
# ActivityInstrumentationTestCase2
# ═══════════════════════════════════════════════════════════════
class ActivityInstrumentationTestCase2(InstrumentationTestCase):
"""ActivityInstrumentationTestCase2 — Activity 测试用例"""
def __init__(self, pkg: str, activity_class: Type):
super().__init__()
self._pkg = pkg
self._activity_class = activity_class
self._activity: Optional[Any] = None
def setActivityIntent(self, intent: Any):
"""设置 Activity Intent"""
pass
def getActivity(self) -> Optional[Any]:
"""获取 Activity 实例"""
return self._activity
def testActivityCreated(self) -> bool:
return self._activity is not None
def testActivityResumed(self) -> bool:
return self._activity is not None
def testActivityStarted(self) -> bool:
return self._activity is not None
def toString(self) -> str:
return (f"ActivityInstrumentationTestCase2("
f"pkg={self._pkg}, cls={self._activity_class})")
# ═══════════════════════════════════════════════════════════════
# ActivityUnitTestCase
# ═══════════════════════════════════════════════════════════════
class ActivityUnitTestCase(InstrumentationTestCase):
"""ActivityUnitTestCase — Activity 单元测试"""
def __init__(self, activity_class: Type):
super().__init__()
self._activity_class = activity_class
self._activity: Optional[Any] = None
def setActivityContext(self, context: Any):
"""设置 Activity 上下文"""
if self._activity and hasattr(self._activity, 'setContext'):
self._activity.setContext(context)
def setApplication(self, application: Any):
"""设置 Application"""
if self._activity and hasattr(self._activity, 'setApplication'):
self._activity.setApplication(application)
def getActivity(self) -> Optional[Any]:
return self._activity
def startActivity(self, intent: Any, bundle: Any = None,
last_non_config_instance: Any = None) -> Any:
"""启动 Activity"""
return self._activity
def toString(self) -> str:
return f"ActivityUnitTestCase(cls={self._activity_class})"
# ═══════════════════════════════════════════════════════════════
# ServiceTestCase
# ═══════════════════════════════════════════════════════════════
class ServiceTestCase(InstrumentationTestCase):
"""ServiceTestCase — Service 测试用"""
def __init__(self, service_class: Type):
super().__init__()
self._service_class = service_class
self._service: Optional[Any] = None
self._service_binder: Optional[Any] = None
self._service_created = False
def getService(self) -> Optional[Any]:
return self._service
def bindService(self, intent: Any) -> Any:
"""绑定 Service"""
return self._service_binder
def bindServiceNotNeeded(self):
"""Service 不需要绑定"""
pass
def setService(self, service: Any):
self._service = service
def testServiceCreated(self) -> bool:
return self._service_created
def testServiceBound(self) -> bool:
return self._service_binder is not None
def testServiceStarted(self) -> bool:
return self._service is not None
def testServiceStopped(self) -> bool:
return not self._service_created
def toString(self) -> str:
return f"ServiceTestCase(cls={self._service_class})"
# ═══════════════════════════════════════════════════════════════
# ProviderTestCase2
# ═══════════════════════════════════════════════════════════════
class ProviderTestCase2(InstrumentationTestCase):
"""ProviderTestCase2 — ContentProvider 测试用例"""
def __init__(self, provider_class: Type, provider_authority: str):
super().__init__()
self._provider_class = provider_class
self._provider_authority = provider_authority
self._provider: Optional[Any] = None
self._resolver: Optional[Any] = None
def getProvider(self) -> Optional[Any]:
return self._provider
def getMockContentResolver(self) -> Optional[Any]:
return self._resolver
def setProvider(self, provider: Any):
self._provider = provider
def setMockContentResolver(self, resolver: Any):
self._resolver = resolver
def toString(self) -> str:
return (f"ProviderTestCase2(cls={self._provider_class}, "
f"authority={self._provider_authority})")
# ═══════════════════════════════════════════════════════════════
# ApplicationTestCase
# ═══════════════════════════════════════════════════════════════
class ApplicationTestCase(InstrumentationTestCase):
"""ApplicationTestCase — Application 测试用例"""
def __init__(self, application_class: Type):
super().__init__()
self._application_class = application_class
self._application: Optional[Any] = None
def getApplication(self) -> Optional[Any]:
return self._application
def setApplication(self, application: Any):
self._application = application
def testApplicationCreated(self) -> bool:
return self._application is not None
def toString(self) -> str:
return f"ApplicationTestCase(cls={self._application_class})"
# ═══════════════════════════════════════════════════════════════
# __all__
# ═══════════════════════════════════════════════════════════════
__all__ = [
"InstrumentationTestRunner",
"InstrumentationTestCase",
"ActivityInstrumentationTestCase2",
"ActivityUnitTestCase",
"ServiceTestCase",
"ProviderTestCase2",
"ApplicationTestCase",
"Instrumentation",
]