---
title: "Test Data for Health Connect: Fakes, the Toolbox, and the Generators You Write"
canonical: "https://aifitnessapi.com/test/health-connect-test-data"
cluster: "Testing"
primary_query: "health connect test data"
last_reviewed: "2026-07-27"
description: "connect-testing is alpha03 from April 2025 and stubs aggregation. What FakeHealthConnectClient proves, what the Toolbox cannot, what you write."
publisher: "AIFitnessAPI — independent, not sponsored"
cite_as: "\"Test Data for Health Connect: Fakes, the Toolbox, and the Generators You Write\", AIFitnessAPI, https://aifitnessapi.com/test/health-connect-test-data"
---

# Test Data for Health Connect: Fakes, the Toolbox, and the Generators You Write

> Insert records into FakeHealthConnectClient, read them back with a page size of 2, and assert every record arrives exactly once — pagination, change tokens, permission checks and thrown exceptions are what the library genuinely proves. The constraint is that androidx.health.connect:connect-testing is still 1.0.0-alpha03, released April 9 2025, ships no fake-data generation API, and stubs aggregation rather than computing it, so a daily-total assertion made through the fake only re-reads the number you handed it. Move the arithmetic into your own pure function and test that against records instead. Use the Toolbox by hand on a device for exploration, never in CI, and write your own generators for the ugly multi-source fixtures.

- Canonical: https://aifitnessapi.com/test/health-connect-test-data
- Last reviewed: 2026-07-27
- Publisher: AIFitnessAPI (https://aifitnessapi.com) — independent, not sponsored
- Cite as: "Test Data for Health Connect: Fakes, the Toolbox, and the Generators You Write", AIFitnessAPI, https://aifitnessapi.com/test/health-connect-test-data

---

A Health Connect read path fails in two ways that both look exactly like success. The first: a paginated read drops a page or replays one, so a user's Tuesday comes back seven thousand steps short or seven thousand steps long, and nothing throws. The second: the user revokes your steps permission from the Health Connect settings screen while a sync is mid-flight, the client throws `SecurityException` on the next call, and your coroutine folds it into an empty list that the UI renders as a confident zero.

Both are catchable in a local unit test, and this is the one Google's testing library is genuinely good at:

```kotlin
@Test
fun `every record arrives exactly once across pages`() = runTest {
    val fake = FakeHealthConnectClient()
    fake.insertRecords(threeDaysOfSteps())   // your generator — see below

    val seen = mutableListOf<String>()
    var token: String? = null
    do {
        val page = fake.readRecords(
            ReadRecordsRequest(
                recordType = StepsRecord::class,
                timeRangeFilter = window,
                pageSize = 2,          // small on purpose
                pageToken = token,
            )
        )
        // Key on an identity YOUR generator controls and always sets.
        // clientRecordId is optional: if the writer left it null, every
        // element collapses to the same value and this test fails for a
        // reason that has nothing to do with pagination.
        page.records.forEach { seen += requireNotNull(it.metadata.clientRecordId) }
        token = page.pageToken
    } while (token != null)

    assertEquals(seen.size, seen.toSet().size)  // nothing repeated
    assertEquals(expectedCount, seen.size)      // nothing dropped
}
```

Google's own guidance is to set "the page size to a small value, such as 2" precisely so pagination gets exercised, and the page closes with a checklist that includes verifying your pagination implementation and "what happens when you fetch multiple pages but one has an expired token". That is the shape of the assertion. Compile the sample above against the library before trusting it — it is composed from the identifiers on Google's page, not copied whole from it.

## The library is real, and it has been standing still since April 2025

Add it as a test dependency:

```kotlin
testImplementation("androidx.health.connect:connect-testing:1.0.0-alpha03")
```

That version matters more than it looks. As of 2026-07-30 the AndroidX release-notes page lists exactly three releases of `connect-testing` — `1.0.0-alpha01` on September 4 2024, `1.0.0-alpha02` on February 26 2025, and `1.0.0-alpha03` on April 9 2025. There has been nothing since. Over the same window the runtime client moved on: `androidx.health.connect:connect-client` is stable at 1.1.0 with 1.2.0-alpha04 in alpha, and its release notes carry an April 22 2026 update stamp. So the thing you test with is roughly fifteen months behind the thing you are testing, and the docs page opens with a note that the library "is in alpha, so future versions might include breaking changes."

That is not a reason to skip it. It is a reason to know its three documented holes before you build a suite on top of it, because two of them will silently weaken your assertions.

## Hole one: aggregation is stubbed, and a stubbed aggregate makes a test that cannot fail

Google states it plainly: "Aggregation calls don't have fake implementations. Instead, aggregation calls use stubs that you can program to behave in a certain way."

Read that again with a test in hand. `FakeHealthConnectClient` does no arithmetic over the records you inserted. If you insert a week of `StepsRecord` and then call `aggregate`, you get back whatever `AggregationResult` you programmed into `fake.overrides.aggregate` — and then you assert that it equals the value you just wrote. The test is a mirror. It will keep passing after you break your time-range filter, after you double-count an overlapping interval from a second `dataOrigin`, and after a daylight-saving night pushes a session into the wrong local day. An assertion that cannot fail is worse than no assertion, because in a coverage report it reads as protection.

The fix is not a cleverer stub. It is moving the arithmetic somewhere a test can reach:

```kotlin
// Yours. Pure. Takes records, returns totals. A test of this can fail.
fun dailyTotals(records: List<StepsRecord>, zone: ZoneId): Map<LocalDate, Long>
```

Then the interesting assertions become possible — a session that straddles local midnight splitting across two days, two overlapping records from different sources resolving to one contribution rather than two, a 23-hour DST day totalling correctly. Those are the bugs that reach production; see [day boundaries and time zones](/architecture/timezones-and-day-boundaries) and [deduplicating health data](/architecture/deduplicate-health-data) for what the correct behaviour is, and treat this page as where you prove you implemented it.

The stub is still worth having, for the two jobs it can actually do. Feed a known aggregate through to check how your UI renders it:

```kotlin
fake.overrides.aggregate = stub(
    AggregationResult(
        metrics = buildMap {
            put(HeartRateRecord.BPM_AVG, 74.0)
            put(ExerciseSessionRecord.EXERCISE_DURATION_TOTAL, Duration.ofMinutes(30))
        }
    )
)
```

And make any call throw, which is the library's best feature:

```kotlin
fake.overrides.insertRecords = stub { throw RemoteException() }
```

Google documents `insertRecords` as throwing `android.os.RemoteException` "for any IPC transportation failures", `SecurityException` "for requests with unpermitted access", and `java.io.IOException` "for any disk I/O issues". Each of those is one line of setup and one real assertion about what your sync does next.

## Hole two: permissions can be emulated, but only coarsely

```kotlin
val permissions = FakePermissionController(grantAll = false)
val fake = FakeHealthConnectClient(permissionController = permissions)
```

Google's caution on the same page is the one to design around: "You should also have tests to verify correct behavior when the client throws a `SecurityException`. Users can revoke permissions at any time." Mid-sync revocation is not an edge case for a health app, it is a Tuesday — and the correct behaviour is almost never "render zero". It is to leave the last known value in place, mark the range unknown, and re-request. That is the assertion worth writing.

One limit, checked on 2026-07-30: `grantAll` is the only `FakePermissionController` parameter the documentation demonstrates. If you need a fake that grants read-steps but denies read-heart-rate, do not assume a per-permission API exists because it would be sensible — check the current API reference first.

If it is not there, the workaround is the same move this whole page argues for: put the permission check behind an interface you own, one method per question your sync actually asks, and let the fake answer per metric. That is a two-line indirection and it buys you the branch coverage the library will not — the case where steps are granted and heart rate is denied, which is the mixed state that produces a day with a plausible step count and a silently absent resting heart rate. Test that branch against your own double, and keep `FakePermissionController` for the coarse all-or-nothing case it does cover. Moving logic to where a test can reach it is the answer every time the platform tooling stops short.

## Hole three: no fake-data generation, so the fixtures are your job

Verbatim from Google: "The library doesn't include APIs to generate fake data yet, but you can use the data and generators used by the library in Android Code Search." That link points at `TestData.kt` inside the library's own test source set. It is internal test code, not public API — copying from it is a workaround with no compatibility promise attached.

So you write the generators. `MetadataTestHelper` covers one narrow but important part of it: it provides "the `populatedWithTestValues()` extension function, which simulates Health Connect populating metadata values during record insertion." That matters because a record you construct in a test has empty metadata, while a record read back out of Health Connect does not — and `dataOrigin`, `clientRecordId` and `recordingMethod` are exactly the fields your dedupe and attribution logic keys on. A fixture without them tests a code path your app never runs. Note that the release notes name the function two ways, `MetadataTestHelper#populatedWithTestValues` and `Metadata.populatedWithTestValues`; confirm the receiver against the API reference before you compile.

Everything past metadata is unwritten. The fixtures worth building are the ugly ones: two apps writing overlapping step intervals for the same wall-clock hour, a sleep session retro-edited three days later, a device whose clock is two minutes fast, a record set that spans a DST transition, a page whose change token has expired. [Mocking wearable data](/test/mock-wearable-data) covers what those fixtures should contain in detail; the Health-Connect-specific requirement is that each generated record carries plausible metadata, because a generator that stamps every record with one `dataOrigin` cannot produce the multi-source conflict that is the whole reason dedupe exists.

## The Toolbox is a second tool, and it is not the same tool

Google's other offering is the Health Connect Toolbox: "a companion developer tool to help you test your app's integration with Health Connect. It can read and write data directly to Health Connect, allowing you to test your app's operations." You download a ZIP, extract it, and install the APK with `adb`:

```
$ adb install HealthConnectToolbox-{Version Number}.apk
```

The page carries no version number — you read it off the extracted filename, and Google notes the number "is expected to be updated with each release."

It supports reading and writing all Health Connect data types, and it is the only way to get a *peer app* writing into the on-device store, which is what makes cross-app attribution testable at all. Insert steps from the Toolbox, read them from your app, and check that you attribute them to the Toolbox's `dataOrigin` and not to yourself.

But do not put it in a pipeline. Every documented interaction is a tap sequence — "Tap on `Insert Health Record`", select a category, select a type, enter the value, tap `SAVE` — and there is no documented CLI, intent, broadcast, content provider, or instrumentation surface. The only automatable step is the `adb install`. Google does not actually say the Toolbox is manual-only; it says nothing either way, and this is our reading of a page (last updated 2026-01-19) that documents nothing but GUI. Treat it as a manual on-device exploration tool: excellent for ten minutes of poking at a permission flow before a release, useless as a fixture loader, and with no way to seed a known dataset reproducibly.

## Google's recommended test cases, described accurately

Google publishes a list at `health-connect/test/test-cases`, framed as: "You are responsible for testing your applications and verifying users have a positive and consistent experience. Health Connect recommends a list of test cases that are designed to conform with best practices and user experience guidelines."

There are ten numbered cases and thirteen actual sections, because 02 and 04 subdivide — onboarding permission requests, integrating and unlinking, reaching Health Connect from your settings, denying and allowing permissions, then write, read, read-aggregated, update, display and delete. Each has explicit PASS and FAIL conditions, which makes them a usable manual release checklist. The page also carries a caution that "test cases are continuously evolving", so re-read it rather than forking it into your wiki.

What the page does not say, in either direction, is anything about Google Play. We full-text searched it on 2026-07-30 for "Play", "approv" and "mandat" and every hit was navigation chrome. So: these are recommendations, and a completed checklist is not a review artifact you can point at — but nor is there a Google statement anywhere on that page exempting you from anything. Do not carry either belief into a release meeting. The declaration obligation is separate and real: the release notes state developers must declare read and/or write access for the data types their apps use, which is a form to fill in, not a test to run. [Integrating Health Connect](/integrate/google-health-connect) covers that setup path.

## Where the ladder stops

`FakeHealthConnectClient` is a local unit test tool. Google's own framing is that you use it to "verify the behavior of the classes in your app that interact with the Health Connect client" — your classes, not Health Connect. It does not exercise the real Health Connect APK, the system permission UI, the IPC boundary, or on-device storage. A suite that is green against the fake tells you your code is internally consistent; it tells you nothing about whether the permission sheet appeared.

And there is no documented instrumented-test recipe for that sheet. The `test/` subtree on developer.android.com has exactly three pages — unit tests, test cases, and the Toolbox — and none of them covers Espresso or UI Automator against the permission controller. The manual cases `hc-01`, `hc-04-01`, `hc-04-02` and `hc-02-03` are Google's answer, and they are tap-through steps for a human. One thing that helps, though it is our inference rather than a Google recipe: your permissions-rationale activity is reached through an exported intent filter, so an instrumented test can launch it directly instead of tapping through Health Connect to find it.

The honest split, then. Pagination, change tokens, permission-check ordering, thrown exceptions and your own aggregation arithmetic go in CI against the fake, and they should be strict enough to fail. The permission UI, cross-app attribution and anything involving real on-device storage go in a manual device pass with the Toolbox open. Aggregates coming back from the real client get reconciled in production against your own totals rather than asserted in a test — because that comparison is the only one where the two numbers were computed by two different implementations. If your app is showing an empty screen today rather than a failing test tomorrow, start at [Health Connect returning no data](/fix/health-connect-no-data) instead.

## FAQ

### Does FakeHealthConnectClient compute aggregates from the records I insert?

No. Google documents that aggregation calls have no fake implementations and use stubs you program instead, accessed through the overrides property. The fake does no arithmetic over inserted records, so a test that inserts a week of steps, calls aggregate, and asserts on the total is asserting on the AggregationResult it programmed a moment earlier. That test cannot fail, which is worse than having no test, because a coverage report counts it as protection. Put the bucketing and summing in your own pure function that takes records and returns totals, test that directly, and reserve the stub for checking how your UI renders a known value and for making calls throw.

[Permalink](https://aifitnessapi.com/test/health-connect-test-data#faq-1)

### Which version of the Health Connect testing library is current, and is it still being developed?

As of 2026-07-30 the latest published version is 1.0.0-alpha03, released April 9 2025. The AndroidX release notes list exactly three releases: alpha01 on September 4 2024, alpha02 on February 26 2025, and alpha03 on April 9 2025, with nothing after. Over the same period the runtime client kept moving and is stable at 1.1.0 with 1.2.0-alpha04 in alpha. The docs page also opens with a note that the library is in alpha and future versions might include breaking changes. Use it, but do not plan around new capabilities arriving.

[Permalink](https://aifitnessapi.com/test/health-connect-test-data#faq-2)

### Can I drive the Health Connect Toolbox from a CI script to seed data?

Not in any documented way. The only scriptable step is installing the APK with adb after extracting it from the downloaded ZIP. Every other interaction Google documents is a tap sequence through the app: insert a health record, pick a category, pick a type, enter a value, save. There is no documented CLI, intent, broadcast, content provider or instrumentation surface. Google does not state that the tool is manual only, and it does not state the opposite either; reading it as a manual exploration tool is the only conclusion the documentation supports. Its real value is that it is a peer app writing into the on-device store, which is the one way to test cross-app attribution.

[Permalink](https://aifitnessapi.com/test/health-connect-test-data#faq-3)

### Do I have to complete Google's recommended Health Connect test cases before shipping?

Google frames them as recommendations: the page says you are responsible for testing your applications and that Health Connect recommends a list of test cases designed to conform with best practices and user experience guidelines. There are ten numbered cases and thirteen sections, since 02 and 04 subdivide, each with explicit pass and fail conditions, which makes them a decent manual release checklist. The page says nothing about Google Play in either direction — we searched its full text on 2026-07-30 for Play, approv and mandat and every hit was navigation chrome. So do not treat a completed checklist as a review artifact, and do not assume anyone has exempted you from anything. The separate and genuinely mandatory item is declaring read or write access for the data types your app uses.

[Permalink](https://aifitnessapi.com/test/health-connect-test-data#faq-4)

### How do I test what happens when a user revokes a Health Connect permission mid-sync?

Construct FakePermissionController with grantAll set to false, pass it into FakeHealthConnectClient as the permissionController, and assert on what your sync does when the client throws SecurityException. Google's own caution says you should have tests verifying correct behaviour when the client throws it, because users can revoke permissions at any time. The behaviour worth asserting is that you keep the last known value and mark the range unknown rather than rendering a zero, since a zero step count is a claim about the user's day rather than an absence of data. One limit checked on 2026-07-30: grantAll is the only constructor parameter the documentation demonstrates, so verify against the current API reference before assuming a per-permission grant or revoke call exists.

[Permalink](https://aifitnessapi.com/test/health-connect-test-data#faq-5)
