iOS Testing Strategy
Last Updated: 2025-11-21
Current State
Manual Testing Only
- All iOS features tested manually on simulator
- No automated UI tests
- No unit tests for ViewModels
- Smoke tests documented in PR descriptions
Risk: Regressions not caught until user testing
Recommendation: Add XCUITest Coverage
Phase 2f: iOS UI Testing
Priority: Medium (deferred but recommended before Phase 2 completion) Effort: 8-10 hours
Setup
- Create UI test target in Xcode
- Configure test schemes
- Set up test data fixtures
- Create helper methods for common interactions
Test Coverage Goals
Phase 2a: Round Creation
- ✅ Quick Start templates fill correctly
- ✅ Manual entry with validation
- ✅ Error states display
- ✅ Form reset works
Phase 2d: Active Scoring
- ✅ Score entry workflow
- ✅ End completion
- ✅ Undo functionality
- ✅ Running total calculations
Phase 2c: Round List
- ✅ List displays rounds
- ✅ Navigation works
- ✅ Empty state
- ✅ Pull-to-refresh
Example XCUITest
import XCTest
class RoundCreationUITests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
app.launch()
}
func testQuickStart18mIndoor() throws {
// Navigate to Rounds tab
app.tabBars.buttons["Rounds"].tap()
// Tap Create Round
app.navigationBars.buttons["plus"].tap()
// Tap 18m Indoor template
app.buttons["18m Indoor"].tap()
// Verify form fields populated
XCTAssertEqual(app.textFields["Round Name"].value as? String, "18m Indoor Practice")
XCTAssertEqual(app.textFields["Ends"].value as? String, "10")
XCTAssertEqual(app.textFields["Arrows per End"].value as? String, "3")
// Verify summary card
XCTAssertTrue(app.staticTexts["Total Arrows: 30"].exists)
// Create round
app.buttons["Create Round"].tap()
// Verify success (navigation or message)
// Implementation depends on Phase 2b/2d navigation
}
func testValidationPreventsInvalidSubmission() throws {
app.tabBars.buttons["Rounds"].tap()
app.navigationBars.buttons["plus"].tap()
// Clear Round Name
let roundNameField = app.textFields["Round Name"]
roundNameField.tap()
roundNameField.clearText()
// Verify Create button disabled
XCTAssertFalse(app.buttons["Create Round"].isEnabled)
}
}
extension XCUIElement {
func clearText() {
guard let stringValue = self.value as? String else {
return
}
var deleteString = String()
for _ in stringValue {
deleteString += XCUIKeyboardKey.delete.rawValue
}
self.typeText(deleteString)
}
}CI/CD Integration
Future Consideration: GitHub Actions for iOS
name: iOS Tests
on: [push, pull_request]
jobs:
test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: |
cd iosApp
xcodebuild test \
-scheme ArcheryApprentice \
-destination 'platform=iOS Simulator,name=iPhone 15,OS=latest'Success Criteria
Phase 2 testing complete when:
- ✅ XCUITest target configured
- ✅ Round creation tests passing
- ✅ Score entry tests passing
- ✅ Round list tests passing
- ✅ Test coverage matches Android level
Recommendation: Implement Phase 2f before marking Phase 2 complete to establish quality baseline for future phases.