Skip to content

feat(testing): Add testing infrastructure with Kover and test utilities#3520

Merged
ahmedre merged 6 commits intoquran:mainfrom
ksalhab89:feature/testing-infrastructure-phase1
Feb 22, 2026
Merged

feat(testing): Add testing infrastructure with Kover and test utilities#3520
ahmedre merged 6 commits intoquran:mainfrom
ksalhab89:feature/testing-infrastructure-phase1

Conversation

@ksalhab89
Copy link
Copy Markdown
Contributor

Summary

Implements Phase 1 of the testing infrastructure initiative as discussed in #3516.

  • Add Kover code coverage plugin with proper exclusions for generated code
  • Create common:test-utils module with shared testing utilities
  • Add TestDataFactory using real domain models (SuraAyah, Bookmark, Tag, RecentPage)
  • Add RxSchedulerRule for synchronous RxJava testing
  • Add TestDispatcherRule for coroutine testing
  • Add Flow testing extensions with Turbine
  • Remove MockK dependency (prefer fakes over mocks per maintainer feedback)
  • Fix pre-existing broken tests in audio modules
  • Add comprehensive TESTING_STRATEGY.md documentation

Changes

Commit Description
feat(testing) Add Kover plugin and test-utils module
test(core) Add comprehensive tests for QuranInfo
refactor(testing) Remove MockK, prefer fakes
refactor(testing) Improve test infrastructure quality
fix(tests) Fix pre-existing broken tests in audio modules

Test Results

  • 128 tests passing, 0 failures
  • All modules compile and lint checks pass
  • Kover coverage report generates successfully

Test Plan

  • All existing tests pass
  • New QuranInfo tests pass
  • Fixed audio module tests pass
  • Lint checks pass
  • Kover report generates

Closes #3516

- Add Kover plugin for code coverage reporting with exclusions for
  generated code (DI factories, databinding, etc.)
- Create common:test-utils module with shared test infrastructure:
  - TestDispatcherRule for coroutines testing
  - RxSchedulerRule for RxJava testing
  - FlowTestExtensions with Turbine-based helpers
  - TestDataFactory for Quran-specific test fixtures
  - Base test classes for coroutines, RxJava, and combined tests
- Add MockK dependency for Kotlin-first mocking
- Add comprehensive TESTING_STRATEGY.md documenting the testing approach

This establishes the foundation for comprehensive test coverage
following TDD principles and the testing pyramid approach.
Expand QuranInfo test coverage from 6 to 46 tests covering:
- Juz calculations (boundaries, within-juz, display juz)
- Page validation (valid/invalid pages)
- Sura operations (page numbers, sura from page, ayah counts)
- Ayah operations (IDs, lookups, diffs)
- Page lookups (bounds, verse ranges, sura/ayah to page)
- Rub'/Quarter and Manzil lookups
- Dual page mapping (single to dual, dual to single, round-trip)
- Position/navigation calculations (ViewPager)
- Data integrity verification against data source

Tests include boundary conditions, invalid inputs, and edge cases
to ensure robustness of the core Quran metadata operations.
Per maintainer feedback, remove MockK dependency and update
TESTING_STRATEGY.md to reflect fakes-first approach:

- Remove MockK from libs.versions.toml
- Remove MockK from app and test-utils dependencies
- Update all examples to use fake implementations
- Add section explaining fakes vs mocks philosophy
- Update test templates to use fakes pattern
Phase A (P0):
- Rewrite TestDataFactory to use real domain models (SuraAyah, Bookmark,
  Tag, RecentPage) instead of duplicate test classes
- Add dependency on common:data module for real model access

Phase B (P1):
- Fix RxSchedulerRule exception handling: track RxAndroid availability
  state explicitly, only catch NoClassDefFoundError (expected when
  RxAndroid not in classpath)
- Fix Kover exclusion patterns: change *Module to *_Module and *Module_*
  to avoid excluding real business classes

Phase C (P2):
- Remove unused base test classes (BaseCoroutineTest, BaseRxTest,
  BaseCombinedTest) - favor composition over inheritance
- Trim TESTING_STRATEGY.md from 1042 to 304 lines (71% reduction)
- AudioUpdaterTest: Update QariItem constructor calls to include
  opusUrl parameter (null) added in recent refactor
- GaplessAudioInfoCommandTest: Add missing allowedExtensions parameter
  to gaplessDownloads() calls
- GappedAudioInfoCommandTest: Add missing allowedExtensions parameter
  to gappedDownloads() calls

These tests were broken before this PR due to production code changes
that weren't reflected in the test files.
@github-actions
Copy link
Copy Markdown

OLD: app-madani-debug.apk (signature: V1, V2)
NEW: app-madani-debug.apk (signature: V1, V2)

          │           compressed           │          uncompressed          
          ├───────────┬───────────┬────────┼───────────┬───────────┬────────
 APK      │ old       │ new       │ diff   │ old       │ new       │ diff   
──────────┼───────────┼───────────┼────────┼───────────┼───────────┼────────
      dex │  20.1 MiB │  20.1 MiB │ +390 B │  50.6 MiB │  50.6 MiB │ -136 B 
     arsc │   2.1 MiB │   2.1 MiB │    0 B │   2.1 MiB │   2.1 MiB │    0 B 
 manifest │   5.6 KiB │   5.6 KiB │    0 B │  26.2 KiB │  26.2 KiB │    0 B 
      res │   1.8 MiB │   1.8 MiB │    0 B │     2 MiB │     2 MiB │    0 B 
   native │  82.6 KiB │  81.8 KiB │ -780 B │  36.5 KiB │  36.5 KiB │    0 B 
    asset │   1.6 MiB │   1.6 MiB │    0 B │   3.8 MiB │   3.8 MiB │    0 B 
    other │ 200.1 KiB │ 200.1 KiB │   -8 B │ 501.5 KiB │ 501.5 KiB │    0 B 
──────────┼───────────┼───────────┼────────┼───────────┼───────────┼────────
    total │  25.9 MiB │  25.9 MiB │ -398 B │  59.1 MiB │  59.1 MiB │ -136 B 

@github-actions
Copy link
Copy Markdown

Upgraded Dependencies
androidx.activity:activity:1.12.3, (changed from 1.12.4)
androidx.activity:activity-compose:1.12.3, (changed from 1.12.4)
androidx.activity:activity-ktx:1.12.3, (changed from 1.12.4)

Copy link
Copy Markdown
Contributor

@ahmedre ahmedre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

جزاكم الله خيراً looks good
2 minor comments

/**
* Creates multiple bookmarks for testing.
*/
fun createBookmarks(count: Int): List<Bookmark> =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these need to be valid since this is likely to generate incorrect (invalid) sura/ayah bookmarks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! You're right - removed for now. Will add back in Phase 1 when implementing BookmarksDaoImpl tests (15+ tests). Fixed in 4e1dc3c.

Comment thread gradle/libs.versions.toml Outdated
truth = { module = "com.google.truth:truth", version.ref = "truthVersion" }
turbine = { module = "app.cash.turbine:turbine-jvm", version.ref = "turbineVersion" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutinesVersion" }
sqldelight-sqlite-driver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right - not needed yet. Removed for now, will add back when implementing BookmarksDaoImpl and database integration tests. Fixed in 4e1dc3c.

@ahmedre
Copy link
Copy Markdown
Contributor

ahmedre commented Feb 12, 2026

would also be nice to kill Mockito in the future in sha' Allah

- Remove createBookmarks() function (unused, will add in Phase 1 when needed)
- Remove sqldelight-sqlite-driver dependency (will add for BookmarksDao tests)

Addresses review feedback from @ahmedre
@ksalhab89
Copy link
Copy Markdown
Contributor Author

Future Work: Mockito Removal

Planning to remove Mockito as part of Phase 2 and/or 3, in sha' Allah.

Current state:

  • 7 test files using Mockito (~100 mock calls)
  • Mocking: Context, Resources, QuranSettings, BookmarksDBAdapter, models

Strategy:

  • Phase 2: Create fakes naturally while writing new presenter/model tests (30+ tests)
  • Phase 2/3: Migrate existing tests to use fakes instead of mocks
  • Aligns with "fakes over mocks" philosophy

This approach ensures fakes are built with real use cases rather than upfront guesswork.

@github-actions
Copy link
Copy Markdown

OLD: app-madani-debug.apk (signature: V1, V2)
NEW: app-madani-debug.apk (signature: V1, V2)

          │            compressed            │           uncompressed           
          ├───────────┬───────────┬──────────┼───────────┬───────────┬──────────
 APK      │ old       │ new       │ diff     │ old       │ new       │ diff     
──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────
      dex │  20.1 MiB │  20.1 MiB │   -633 B │  50.6 MiB │  50.6 MiB │ -1.2 KiB 
     arsc │   2.1 MiB │   2.1 MiB │      0 B │   2.1 MiB │   2.1 MiB │      0 B 
 manifest │   5.6 KiB │   5.6 KiB │      0 B │  26.2 KiB │  26.2 KiB │      0 B 
      res │   1.8 MiB │   1.8 MiB │      0 B │     2 MiB │     2 MiB │      0 B 
   native │  81.3 KiB │  82.6 KiB │ +1.2 KiB │  36.5 KiB │  36.5 KiB │      0 B 
    asset │   1.6 MiB │   1.6 MiB │      0 B │   3.8 MiB │   3.8 MiB │      0 B 
    other │ 200.1 KiB │ 200.1 KiB │     -6 B │ 501.5 KiB │ 501.5 KiB │      0 B 
──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────
    total │  25.9 MiB │  25.9 MiB │   +627 B │  59.1 MiB │  59.1 MiB │ -1.2 KiB 

@github-actions
Copy link
Copy Markdown

Upgraded Dependencies
androidx.compose.animation:animation:1.10.2, (changed from 1.10.3)
androidx.compose.animation:animation-android:1.10.2, (changed from 1.10.3)
androidx.compose.animation:animation-core:1.10.2, (changed from 1.10.3)
androidx.compose.animation:animation-core-android:1.10.2, (changed from 1.10.3)
androidx.compose.foundation:foundation:1.10.2, (changed from 1.10.3)
androidx.compose.foundation:foundation-android:1.10.2, (changed from 1.10.3)
androidx.compose.foundation:foundation-layout:1.10.2, (changed from 1.10.3)
androidx.compose.foundation:foundation-layout-android:1.10.2, (changed from 1.10.3)
androidx.compose.material:material:1.10.2, (changed from 1.10.3)
androidx.compose.material:material-android:1.10.2, (changed from 1.10.3)
androidx.compose.material:material-ripple:1.10.2, (changed from 1.10.3)
androidx.compose.material:material-ripple-android:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime-android:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime-annotation:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime-annotation-android:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime-retain:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime-retain-android:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime-saveable:1.10.2, (changed from 1.10.3)
androidx.compose.runtime:runtime-saveable-android:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-android:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-geometry:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-geometry-android:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-graphics:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-graphics-android:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-text:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-text-android:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-tooling-preview:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-tooling-preview-android:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-unit:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-unit-android:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-util:1.10.2, (changed from 1.10.3)
androidx.compose.ui:ui-util-android:1.10.2, (changed from 1.10.3)
androidx.compose:compose-bom:2026.01.01, (changed from 2026.02.00)
dev.zacsweers.metro:runtime:0.10.1, (changed from 0.10.3)
dev.zacsweers.metro:runtime-jvm:0.10.1, (changed from 0.10.3)

@ahmedre ahmedre added this pull request to the merge queue Feb 22, 2026
Merged via the queue into quran:main with commit 4ab3121 Feb 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Improve Test Coverage Infrastructure

2 participants