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 行代码
This commit is contained in:
1 parent
8ad62be068
commit
506f9ac725
43 files changed
+16704
-23
No files matched your search
@@ -0,0 +1,485 @@
|
||||
"""
|
||||
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",
|
||||
]
|
||||
Reference in new issue
Block a user