From 623d859c97a30921e16780b64227f94ef5b0f09e Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Thu, 8 Oct 2026 12:36:40 +0800 Subject: [PATCH] =?UTF-8?q?test(mutual):=20=E9=92=89=E6=AD=BB=20fixture=20?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=9F=BA=E5=87=86=EF=BC=8C=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E6=97=B6=E6=AE=B5=E6=80=A7=20flaky?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixture 用 2024-03-09 固定 ISS TLE + System.currentTimeMillis() 起点;SGP4 带阻力衰减 942 天后高度仅 ≈262km,12h 窗口内可能无广州过境 → 3 条依赖过境窗的用例时段性失败(Gradle 缓存 FROM-CACHE 会掩盖上一次的真跑)。 - TestOrbits.FIXTURE_BASE(2024-03-10T00:00Z,历元后约 18h)取代默认 System.currentTimeMillis() - MutualViewModel 墙钟可注入:nowMillis: () -> Long = System::currentTimeMillis(第 4 个默认参数,生产行为逐位不变;工厂具名构造零改动) - 断言里的 now 改用同一基准;prefill/scroll 测试不碰时间未动 修后::feature:mutual 28/28,全量 ./gradlew test 451/451。 --- .../look4sat/feature/mutual/MutualViewModel.kt | 7 +++++-- .../look4sat/feature/mutual/MutualViewModelTest.kt | 6 ++++-- .../rtbishop/look4sat/feature/mutual/TestOrbits.kt | 11 ++++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt index 0020d534..2188d90e 100644 --- a/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt +++ b/feature/mutual/src/main/java/com/rtbishop/look4sat/feature/mutual/MutualViewModel.kt @@ -82,7 +82,10 @@ class MutualViewModel( private val settingsRepo: ISettingsRepo, // Injected so unit tests can run the pass computation on a test dispatcher; // production callers keep the CPU-bound pool default. - private val computeDispatcher: CoroutineDispatcher = Dispatchers.Default + private val computeDispatcher: CoroutineDispatcher = Dispatchers.Default, + // Injected so unit tests can pin the wall clock to the fixture TLE epoch and + // stay deterministic; production callers keep the real clock default. + private val nowMillis: () -> Long = System::currentTimeMillis ) : ViewModel() { private val _uiState = MutableStateFlow(MutualUiState()) @@ -303,7 +306,7 @@ class MutualViewModel( queryGeneration += 1 viewModelScope.launch { - val now = System.currentTimeMillis() + val now = nowMillis() // 转发器类型筛选: 使用硬编码 AMSAT Live 清单 (见 Sources): // FM = {SO-50, ISS ZARYA, AO-123}, Linear = {RS-44, FO-29, // AO-7, AO-73, JO-97}. 不再依赖 AMSAT 网页同步: 任何网络下都 diff --git a/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/MutualViewModelTest.kt b/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/MutualViewModelTest.kt index 8077b90c..d3942037 100644 --- a/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/MutualViewModelTest.kt +++ b/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/MutualViewModelTest.kt @@ -53,7 +53,9 @@ class MutualViewModelTest { ): MutualViewModel = MutualViewModel( satelliteRepo = FakeSatelliteRepo(satellites, passes), settingsRepo = FakeSettingsRepo(position), - computeDispatcher = StandardTestDispatcher(mainDispatcherRule.dispatcher.scheduler) + computeDispatcher = StandardTestDispatcher(mainDispatcherRule.dispatcher.scheduler), + // Pin the clock to the fixture base so results never depend on wall time. + nowMillis = { TestOrbits.FIXTURE_BASE } ) private fun TestScope.queryAndSettle(vm: MutualViewModel) { @@ -219,7 +221,7 @@ class MutualViewModelTest { assertTrue(state.mutualPasses.all { it.catNum == 25544 }) assertTrue(state.mutualPasses.all { it.name == "ISS (ZARYA)" }) // AOS/LOS within the searched horizon - val now = System.currentTimeMillis() + val now = TestOrbits.FIXTURE_BASE assertTrue(state.mutualPasses.all { it.startTime >= now - 120_000L }) assertTrue(state.mutualPasses.all { it.endTime <= now + 12 * 3600_000L + 120_000L }) } diff --git a/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/TestOrbits.kt b/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/TestOrbits.kt index 8acce29a..743bd1f0 100644 --- a/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/TestOrbits.kt +++ b/feature/mutual/src/test/java/com/rtbishop/look4sat/feature/mutual/TestOrbits.kt @@ -48,6 +48,15 @@ object TestOrbits { ) ) + /** + * Fixed wall-clock base for every fixture computation: 2024-03-10T00:00Z, + * ~18 h after [ISS]'s TLE epoch, so SGP4 propagates an accurate, healthy + * orbit. Tests pin the ViewModel clock to this value as well + * (MutualViewModel.nowMillis), which makes pass windows deterministic + * instead of rotting as the fixture ages against System.currentTimeMillis(). + */ + val FIXTURE_BASE: Long = 1710028800000L + /** Guangzhou (default BA7OPF grid OL62/OL63 area). */ val GUANGZHOU = GeoPos(23.13, 113.26) @@ -85,7 +94,7 @@ object TestOrbits { fun findPassWindows( sat: OrbitalObject = ISS, pos: GeoPos = GUANGZHOU, - time: Long = System.currentTimeMillis(), + time: Long = FIXTURE_BASE, hoursAhead: Int = 12 ): List { if (!sat.willBeSeen(pos)) return emptyList()