""" 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", ]