Repository navigation
Testing Documentation
YewonDanaLee edited this page Oct 21, 2026
·
2 revisions
| Version | Date | Key Changes | Author |
|---|---|---|---|
| v0.1.0 | 2026-10-21 | Iteration 2: Test Responsibility & Schedule, Unit & Integration Testing (plan and first results) | Yewon Lee |
Whoever writes a feature also writes its tests, in the same PR. Each part has one person who keeps its tests working.
| Component (layer) | Files | Maintainer |
|---|---|---|
| Backend: route generation & street graph |
api/route_algorithm/algorithm.py, street_graph.py
|
Yewon Lee |
| Backend: elevation, scoring, LLM briefing |
api/route_algorithm/elevation.py, scoring.py, briefing.py, llm.py
|
Yewon Lee |
| Backend: traffic signal counting | signal counting in algorithm.py
|
SoonYoung Park |
| Backend: accounts API | api/views/auth.py |
Anton (log-in, Google, log-out), Yewon Lee (sign-up validation) |
| Backend: saved routes API |
api/views/routes.py, api/models.py
|
Anton |
| Backend: place search |
api/services/tmap.py, place_translation.py, api/views/places.py
|
Yewon Lee |
| Android Model (data layer) |
data/remote, data/repository, data/auth
|
Yewon Lee; elevation in RouteRepository: SoonYoung Park |
| Android ViewModel |
AuthViewModel, MyPageViewModel, route options in RouteViewModel
|
Yewon Lee |
| Android ViewModel (elevation) | elevation and slope parts of RouteViewModel
|
SoonYoung Park |
| Android View (Compose UI) |
ui/**/*Screen.kt, RouteMap.kt
|
Screen authors (manual testing) |
- Before merging a PR, the author runs both test suites and everything has to pass. If the PR touches shared code, the reviewer runs them too.
- Backend:
python manage.py test - Android:
./gradlew :app:testDebugUnitTest
- Backend:
- At the end of each iteration we run all tests and both coverage reports on the latest
iteration-N-democommit and update the Results below. - We don't have CI yet. We plan to run the tests on every PR with GitHub Actions in Iteration 3.
| Component | Test framework | Mocking / fakes | Coverage tool |
|---|---|---|---|
| Backend (Django) | Django test runner (unittest), DRF APITestCase
|
unittest.mock, fake street grid (api/tests/fakes.py), recorded TMAP responses (api/tests/data) |
coverage.py 7.16.2 |
| Android | JUnit 4, kotlinx-coroutines-test |
FakeApiService, fake elevation API, OkHttp MockWebServer, MainDispatcherRule
|
JaCoCo (Android Gradle plugin) |
We set these before measuring anything.
| Layer | Target | Why |
|---|---|---|
Backend route algorithm (api/route_algorithm) |
85% | Main logic of the app (route shape, elevation, score, briefing). Plain Python, easy to test alone. |
Backend API & services (api/views, api/services, api/models.py) |
80% | Input checks and error responses. Some branches only happen when an outside service fails. |
| Android ViewModel | 60% | Screen state (options, save, rename, delete). Can run on the JVM with fakes. |
Android Model (data.*) |
50% | Mostly thin Retrofit / DataStore code. The real logic is in the interceptor and repositories. |
| Android View (Compose UI) | no target | Needs instrumented UI tests. For now we check screens by hand on the emulator. |
- Excluded from backend coverage:
api/tests/*,api/migrations/*(backend/.coveragerc). -
api/management/commands/build_street_graph.pyis counted but has no target. It downloads a 114MB file, so we run it by hand. The code it calls (street_graph.py) has unit tests. - Android: the Gradle plugin already leaves out generated code (
R,BuildConfig). Compose UI has no target. - Tests never call outside services. Overpass, Open-Meteo, Open-Elevation, Gemini, Google and TMAP are mocked or faked. The backend uses Django's test database.
-
api/tests/test_route_flow.pyuses the real Seoul street graph. Ifbackend/data/street_graph/seoul_walk.pklisn't there, it is skipped.
Backend (Python 3.14, from backend/):
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt
python manage.py migrate
python manage.py build_street_graph # needed for the 3 integration tests; otherwise they are skipped
GOOGLE_CLIENT_ID=test coverage run manage.py test
coverage report # coverage html for an HTML reportGOOGLE_CLIENT_ID just has to exist (any value works). Other API keys aren't needed because outside calls are mocked.
Android (Gradle 9.5.0 wrapper, JDK 17+, from android_app/):
./gradlew :app:testDebugUnitTest
./gradlew :app:createDebugUnitTestCoverageReport
# report: app/build/reports/coverage/test/debug/index.html| Component | Frameworks | Target | Actual | Date | Command / Report |
|---|---|---|---|---|---|
| Backend route algorithm | Django test runner, mock, coverage.py | 85% | 88.0% (574/652) ✅ | 10/21 | coverage run manage.py test |
| Backend API & services | Django test runner, mock, coverage.py | 80% | 87.4% (347/397) ✅ | 10/21 | coverage run manage.py test |
| Android Model | JUnit, MockWebServer, JaCoCo | 50% | 69.5% (191/275) ✅ | 10/21 | ./gradlew :app:createDebugUnitTestCoverageReport |
| Android ViewModel | JUnit, coroutines-test, JaCoCo | 60% | 54.6% (288/527) ❌ | 10/21 | ./gradlew :app:createDebugUnitTestCoverageReport |
| Android View | — | — | 6.3% (82/1311) | 10/21 | same |
Totals: backend 85% (925/1094 statements), Android 26.5% (561/2113 lines).
Test counts
- Backend: 103 tests, 103 passed, 0 failed, 0 skipped. This is with the Seoul graph built. Without it, the 3 tests in
test_route_flow.pyare skipped. - Android: 34 tests, 34 passed, 0 failed, 0 skipped.
| Area | Tests | What is checked |
|---|---|---|
Backend test_algorithm.py
|
11 | Loop / point-to-point / shortest-path fallback, 3 distinct options ranked by score, measured climb and signals in the briefing, routes without elevation, traffic signal counting |
Backend test_generate_route.py
|
15 | Route API validation, languages, end point, options with their own temporary route IDs, map server errors (503) |
Backend test_elevation.py
|
12 | 50m sampling, total climb, uphill sections, batching, lookup errors, score formula |
Backend test_street_graph.py
|
7 | Walking filter, building from an OSM file, traffic signals, cutting out an area, Overpass fallback |
Backend test_route_flow.py (integration) |
3 | Start point → loop → elevation / signals → scoring → briefing → save → saved list on the real Seoul graph; point-to-point; no elevation |
| Backend auth / routes / places / LLM / briefing / crossings | 55 |
test_auth 8, test_route_names 5, test_places 11, test_place_translation 8, test_llm 7, test_briefing 10, test_crossings 6 |
Android RouteViewModelOptionsTest
|
10 | Input validation, options, switching, save state per option, retry, reset |
Android MyPageViewModelTest
|
7 | Rename, swipe-to-delete with rollback on failure, reset |
Android AuthInterceptorTest
|
6 | Token header, expired-session detection |
Android ServerMessageTest
|
4 | Server error → localized message mapping |
Android RouteRepositoryTest, RouteGeometryUtilsTest, ExampleUnitTest
|
7 | Slope calculation and route splitting for slope colors |
Android ViewModel is below target (54.6%, target 60%)
-
AuthViewModelis at 0%. It makes its repository from the AndroidApplicationand DataStore, so it can't run in a plain JVM test. - The elevation summary text in
RouteViewModelhas no tests yet. - In Iteration 3 we will pass the repository into
AuthViewModel(or add Robolectric) and test sign-up checks and session handling. SoonYoung will add tests for the elevation summary.
Coverage reports
Backend (coverage.py):

Android (JaCoCo):

Android unit test results:

To be completed in Iteration 3.
To be completed in Iteration 3 (plan) and Iteration 4 (results).
To be completed in Iteration 5.
RunTime Wiki
- Home
- Requirements & Specifications
- Design Documentation
- Testing Documentation
- Daily Standup Meeting Log
AI Collaboration Reports
- Iteration 1
- Iteration 2