A Swift package for generating and importing realistic HealthKit test data in the iOS Simulator.
When building health apps, the iOS Simulator can't generate real health data because it doesn't have sensors. This package lets you:
- Generate synthetic health data with somewhat realistic patterns (heart rate, HRV, sleep, activity, etc.)
- Import data into HealthKit in the simulator for testing
- Use pre-built fixtures for consistent test data across your project or team
- Stream live data continuously to test real-time app behaviour
For unit tests, UI tests, and prototyping health features.
// Package.swift
dependencies: [
.package(url: "https://github.com/aidancornelius/HealthKitUtility", from: "1.0.0")
]
// Your target
.target(
name: "YourApp",
dependencies: [
.product(name: "HealthKitTestData", package: "HealthKitUtility")
]
)Add this to your Info.plist:
<key>NSHealthUpdateUsageDescription</key>
<string>Write test data to HealthKit for app testing</string>Enable the HealthKit capability in your Xcode project.
import HealthKit
import HealthKitTestData
// Request authorization
let healthStore = HKHealthStore()
let types: Set<HKSampleType> = [
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .heartRateVariabilitySDNN)!
]
try await healthStore.requestAuthorization(toShare: types, read: [])
// Generate 7 days of realistic data
let bundle = SyntheticDataGenerator.generateHealthData(
preset: .normal, // or .lowerStress, .higherStress, .edgeCases
manipulation: .smoothReplace,
startDate: Date().addingTimeInterval(-7 * 86400),
endDate: Date(),
seed: 42 // For reproducible data
)
// Import into HealthKit (simulator only)
let writer = HealthKitWriter(healthStore: healthStore)
try await writer.importData(bundle)// Different stress profiles
let normalData = SyntheticDataGenerator.generateHealthData(
preset: .normal,
startDate: weekAgo,
endDate: now
)
let stressedData = SyntheticDataGenerator.generateHealthData(
preset: .higherStress, // Higher HR, lower HRV
startDate: weekAgo,
endDate: now
)
let edgeCases = SyntheticDataGenerator.generateHealthData(
preset: .edgeCases, // Extreme values for testing
startDate: weekAgo,
endDate: now
)Note: HealthKitTestHelpers is for test targets only. Don't import it in production code - it bundles JSON fixture files that increase app size.
// In your test target Package.swift:
.testTarget(
name: "YourAppTests",
dependencies: [
.product(name: "HealthKitTestHelpers", package: "HealthKitUtility")
]
)
// In your test code:
import HealthKitTestHelpers
// Available fixtures:
let normal = HealthKitFixtures.normalWeek // 7 days, normal health (HR 60-80, HRV 30-70)
let highStress = HealthKitFixtures.highStressWeek // 7 days, elevated stress (HR 80-100, HRV 20-40)
let lowStress = HealthKitFixtures.lowStressWeek // 7 days, low stress (HR 55-70, HRV 45-80)
let cycle = HealthKitFixtures.cycleTracking // 28 days with menstrual flow tracking
let edges = HealthKitFixtures.edgeCases // 7 days with extreme values
let active = HealthKitFixtures.activeLifestyle // 7 days, athletic with multiple daily workouts
// Use any fixture
try await writer.importData(HealthKitFixtures.normalWeek)// Generate data every 60 seconds
let config = LiveGenerationConfig(
preset: .normal,
samplingInterval: 60
)
let loop = LiveDataLoop(config: config, writer: writer)
try await loop.start()
// ... data streams continuously ...
loop.stop()// Shift historical data to current dates
let oldData = try loadFromFile("last-week.json")
let currentData = DateTransformation.transposeBundleDatesToToday(oldData)
try await writer.importData(currentData)- Heart rate & resting heart rate
- Heart rate variability (HRV)
- Activity (steps, distance, calories)
- Sleep analysis (light, deep, REM)
- Workouts
- Respiratory rate
- Blood oxygen
- Body temperature
- Wheelchair activity
- Menstrual flow
import XCTest
@testable import YourApp
import HealthKitTestData
class HealthFeatureTests: XCTestCase {
func testHeartRateProcessing() async throws {
// Use mock store for testing
let mockStore = MockHealthStore()
let writer = HealthKitWriter(healthStore: mockStore)
// Generate test data
let bundle = SyntheticDataGenerator.generateHealthData(
preset: .normal,
startDate: Date().addingTimeInterval(-3600),
endDate: Date(),
seed: 42 // Reproducible
)
try await writer.importData(bundle)
// Test your app's logic
let processor = HeartRateProcessor()
let result = try await processor.analyze(bundle.heartRate)
XCTAssertEqual(result.average, 70, accuracy: 5)
}
}- Integration guide - Setup, entitlements, and advanced usage
- Contributing - Contributing and migrating code from the main app
- iOS 18.0+
- Swift 6.0+
- Xcode 16.0+
- iOS Simulator (for importing data - HealthKit write restrictions should prevent imports on physical devices)
SyntheticDataGenerator- Generate realistic health dataHealthKitWriter- Import data into HealthKit (simulator only)LiveDataLoop- Continuously generate and stream dataDateTransformation- Transpose historical data to current dates- All health data models (
HeartRateSample,HRVSample, etc.)
Test targets only, contains JSON fixtures that shouldn't ship in production.
HealthKitFixtures- Pre-built test data bundles:normalWeek- 7 days of typical health datahighStressWeek- 7 days with elevated stress markerslowStressWeek- 7 days with low stress markerscycleTracking- 28-day menstrual cycle with flow trackingedgeCases- 7 days with extreme values for edge case testingactiveLifestyle- 7 days of athletic lifestyle with multiple workouts
import XCTest
import HealthKitTestHelpers
class HeartRateChartUITests: XCTestCase {
func testChartDisplaysData() async throws {
let app = XCUIApplication()
// Populate simulator HealthKit
let bundle = HealthKitFixtures.normalWeek
try await writer.importData(bundle)
app.launch()
// Verify chart renders with data
XCTAssertTrue(app.images["HeartRateChart"].exists)
}
}MIT License - See LICENSE for details.
Built by Aidan Cornelius-Bell for health app testing.
This repository contains the Swift package and the HealthKit Utility companion app.
Work directly in Sources/ and Tests/:
# Run tests
swift test
# Or use Xcode
open Package.swiftThe app uses XcodeGen to generate the Xcode project from project.yml.
First time:
-
Install XcodeGen:
brew install xcodegen
-
Generate the Xcode project:
xcodegen
-
Open the generated project:
open HealthKitExporter.xcodeproj
After changes to project.yml:
Regenerate the project:
xcodegenWhen making changes:
- Don't edit
.xcodeprojdirectly (it's gitignored and regenerated) - Edit
project.ymlfor project configuration changes - Edit source files normally in Xcode
This package is extracted from the HealthKit Utility app (included in this repo), which provides a full GUI for exporting real device data, network streaming, and live generation with background tasks.