Section 12/161 menit
12. Integrasi CI: Xcode Cloud dan GitHub Actions
12. Integrasi CI: Xcode Cloud dan GitHub Actions
JUnit XML Output untuk CI
swift
# Jalankan test dan hasilkan JUnit XML untuk CI parsing
swift test --enable-code-coverage \
--result-bundle-path TestResults.xcresult \
2>&1 | tee test_output.txt
# Atau dengan xcodebuild
xcodebuild test \
-project MyApp.xcodeproj \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \
-resultBundlePath TestResults.xcresult \
CODE_SIGN_IDENTITY="-"
GitHub Actions Workflow
swift
# .github/workflows/test.yml
name: Swift Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- name: Select Xcode
run: sudo xcode-select -switch /Applications/Xcode_16.app
- name: Build and Test
run: |
xcodebuild test \
-project MyApp.xcodeproj \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16,OS=18.0' \
-resultBundlePath TestResults.xcresult \
CODE_SIGN_IDENTITY="-" \
| xcpretty --report junit --output test-results.xml
- name: Upload Test Results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: |
TestResults.xcresult
test-results.xml
- name: Report Test Results
uses: dorny/test-reporter@v1
if: always()
with:
name: Swift Tests
path: test-results.xml
reporter: java-junit
Xcode Cloud ci_scripts
swift
#!/bin/zsh
# ci_scripts/ci_post_xcodebuild.sh
# Jalankan analisis setelah test
if [ "$CI_XCODEBUILD_ACTION" = "test" ]; then
echo "Menganalisis test results..."
# Cek code coverage (minimal 80%)
COVERAGE=$(xcrun xccov view --report --json $CI_RESULT_BUNDLE_PATH \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['lineCoverage'])")
THRESHOLD=0.80
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
echo "ERROR: Code coverage $COVERAGE < $THRESHOLD"
exit 1
fi
echo "Code coverage: $COVERAGE ✓"
fi
Tag-Based Test Filtering di CI
swift
// Tandai test dengan tag
extension Tag {
@Tag static var unit: Self
@Tag static var integration: Self
@Tag static var slow: Self
@Tag static var networkRequired: Self
}
@Test(.tags(.unit))
func testCalculation() { /* ... */ }
@Test(.tags(.integration, .networkRequired))
func testAPIIntegration() async throws { /* ... */ }
@Test(.tags(.slow))
func testHeavyMigration() async throws { /* ... */ }
swift
# Di CI: jalankan hanya unit test (cepat)
xcodebuild test \
-scheme MyApp \
-destination '...' \
-only-testing:"MyAppTests/unit" # Filter berdasarkan tag
# Atau gunakan -skip-testing untuk exclude
# Nightly run: semua test termasuk slow dan integration
xcodebuild test \
-scheme MyApp \
-destination '...' # Tanpa filter — semua test