소개
iOS 앱 및 게임 개발의 끊임없이 진화하는 환경에서 테스트 접근 방식은 중요한 변화를 겪었습니다. 과거에는 "폭포수" 방법론이 테스트를 별도의 단계로 정의하며 주목받았습니다. 하지만 오늘날 조직은 빠른 피드백과 유연성을 우선시하는 반복적이고 민첩한 프로세스로 이동했습니다. 이러한 전환으로 자동화된 테스팅이 중요시되며 제품 품질을 보장하는 방식이 혁신되었습니다. 이 기사에서는 수동 및 자동 테스트 간의 주요 차이점을 탐구하고 민첩한 개발 프레임워크 내에서 자동화된 테스팅의 이점을 살펴보겠습니다.
폭포수 vs. 민첩한 방법론: 패러다임 전환
폭포수 방법론:
전통적인 폭포수 방법론에서는 개발 프로세스가 요구 사항 수집, 설계, 구현, 테스트, 배포 및 지원을 포함한 선형 순서의 단계를 준수합니다. 요구 사항은 프로젝트 초반에 종종 엄격하게 정의되며 테스트는 주로 개발 주기의 끝에서 발생합니다.
민첩한 방법론:
반면에, 민첩한 방법론은 반복적이고 유연한 접근을 채택합니다. 개발 프로세스 전반에 걸쳐 지속적인 피드백과 조정을 허용합니다. 폭포수와는 달리 테스트는 더 이상 독립적인 단계가 아니라 시작부터 지속적으로 통합됩니다. 민첩한 환경에서 자동화된 테스팅이 표준이며, 개발자는 적시에 피드백을 받고 변경되는 요구 사항에 적응할 수 있습니다.
민첩한 iOS 앱 및 게임 개발에서 자동화된 테스팅의 이점
빠른 피드백: 민첩한 환경에서의 자동화된 테스트는 개발자에게 신속한 피드백을 제공하여 문제를 신속하게 감지하고 수정할 수 있도록 도와줍니다. 이러한 기민함은 빠르게 진행되는 iOS 앱 및 게임 개발 업계에서 중요합니다. 회귀 테스팅: 자동화된 테스트는 새로운 코드가 추가되거나 수정될 때 기존 기능이 정상적으로 작동하도록 보장하여 회귀 문제를 방지합니다. 품질 향상: 자동화된 테스트를 지속적으로 실행함으로써 개발자는 프로세스 초기에 결함을 식별하고 제품 품질을 향상시킬 수 있습니다. 이는 지속적 개선의 문화를 조성합니다. 유연성: 민첩한 방법론의 적응력은 자동화된 테스트와 원활하게 조화를 이룹니다. 요구 사항이 변경될 때 테스트를 쉽게 업데이트할 수 있도록 합니다. 이 유연성은 동적인 iOS 개발에서 중요합니다. 효율성: 자동화된 테스팅은 수동 테스트와 비교하여 소요 시간과 노력을 크게 절감합니다. 이로써 개발자는 코딩과 창의성에 집중할 수 있습니다.
iOS에서의 테스트 주도 개발 (TDD)
테스트 주도 개발은 코드를 구현하기 전에 테스트를 작성하는 것을 지지합니다. 이는 코드 구현 세부 정보가 아닌 앱의 동작을 테스트로 캡처합니다. 이 접근 방식은 변경 및 리팩토링이 기존 기능을 손상시키지 않도록 보장하여 코드의 견고성을 증진합니다.
레드, 그린, 리팩터
"레드, 그린, 리팩터" 전략은 유닛 테스트에서 가치 있는 도구입니다. 다음과 같은 과정으로 이루어집니다: 행동을 정의하고 실패하도록 테스트를 작성합니다 (레드). 테스트를 통과하도록 코드를 구현합니다 (그린). 테스트가 계속 성공하면서 코드를 리팩토링합니다 (리팩터). 이 프로세스는 필요한 동작을 유지합니다.
민첩한 세계에서의 수동 테스팅
수동 테스팅은 특히 자동화하기 어려운 시각적 및 탐색적 테스트를 위해 개발 주기에서 여전히 유효한 위치를 차지합니다. 탐색적 테스팅은 특정 기능의 범위를 벗어나 앱의 동작을 조사하고 사용 가능한 기능을 탐색하고 실험하는 것을 포함합니다.
CI/CD: 지속적인 품질 보장
민첩한 환경에서 지속적 통합 및 지속적 배포 (CI/CD)는 중요합니다. 자동화된 CI/CD 파이프라인을 통해 코드 변경이 배포되기 전에 자동화된 테스트를 거치도록 보장합니다. 이는 신속한 피드백을 제공하고 회귀 위험을 줄이는 데 도움을 줍니다. 저희 CI/CD 파이프라인 예시: 작업 공간 정리. 코드 체크아웃. 기본 스키마 설정. 자동화된 테스트 빌드 및 실행. 인증서 및 프로비저닝 프로필 설치. 버전 번호 증가. 앱 빌드 및 아카이빙. 충돌 모니터링을 위한 dSYM 업로드. IPA 파일 생성. TestFlight에 배포. 이 자동화된 파이프라인은 변경 사항이 철저히 테스트되고 수동 개입 없이 배포되는 것을 보장하여 앱의 기능에 대한 신뢰도를 높입니다.
지원 방법
이 콘텐츠는 영원히 무료로 제공되며 마음에 들고 지원하고 싶다면 다른 사람과 공유해주시기 바랍니다. 또한 저희 게임을 다운로드하고 솔직한 리뷰를 남겨주실 수도 있습니다. 질문 및 피드백은 언제든지 환영하며 최선을 다해 답변해드리겠습니다.
오늘 Apple App Store에서 Falling Sky를 다운로드하세요: https://apps.apple.com/app/id6446787964
Falling Sky에 대한 GitHub Actions 파이프라인 YAML 소스 코드는 다음과 같습니다: (소스 코드는 여기서 언급된 위치에 제공하실 수 있습니다.)
name: Falling sky CI/CD
on:
push:
branches: [ "main" ]
workflow_dispatch:
env:
ARCHIVE_SCHEME: "Falling Sky"
APP_NAME: "FallingSky"
BUNDLE_ID: com.fallingsky
jobs:
build:
name: Build and Test default scheme using any available iPhone simulator
runs-on: self-hosted
steps:
- name: Clean Workspace
run: |
rm -rf $GITHUB_WORKSPACE/*
rm -rf $RUNNER_TEMP/*
- name: Checkout
uses: actions/checkout@v3
- name: Set Default Scheme
run: |
scheme_list=$(xcodebuild -list -json | tr -d "\n")
default=$(echo $scheme_list | ruby -e "require 'json'; puts JSON.parse(STDIN.gets)['project']['targets'][0]")
echo $default | cat >default
echo Using default scheme: $default
- name: Build for test
env:
scheme: ${{ 'default' }}
platform: ${{ 'iOS Simulator' }}
run: |
# xcrun xctrace returns via stderr, not the expected stdout (see https://developer.apple.com/forums/thread/663959)
device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"`
if [ $scheme = default ]; then scheme=$(cat default); fi
if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi
file_to_build=`echo $file_to_build | awk '{$1=$1;print}'`
xcodebuild clean build-for-testing -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=$platform,name=$device"
- name: Test
timeout-minutes: 30
env:
scheme: ${{ 'default' }}
platform: ${{ 'iOS Simulator' }}
run: |
# xcrun xctrace returns via stderr, not the expected stdout (see https://developer.apple.com/forums/thread/663959)
device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"`
if [ $scheme = default ]; then scheme=$(cat default); fi
if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi
file_to_build=`echo $file_to_build | awk '{$1=$1;print}'`
xcodebuild test-without-building -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=$platform,name=$device" -test-iterations 3 -retry-tests-on-failure
- name: Install the Apple certificate and provisioning profile
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.DIST_CERT_BASE64 }}
P12_PASSWORD: ${{ secrets.DIST_CERT_P12_PASSWORD }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.PROVISIONING_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# apply provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
- uses: yanamura/ios-bump-version@v1
with:
version: 1.1.0
build-number: ${{ github.run_number }}
- name: Build and archive app
run: |
if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi
file_to_build=`echo $file_to_build | awk '{$1=$1;print}'`
xcodebuild archive -"$filetype_parameter" "$file_to_build" -scheme "$ARCHIVE_SCHEME" -archivePath "$APP_NAME" -configuration Release
- name: Install Sentry CLI
run: |
# Check if sentry-cli is already installed
if ! command -v sentry-cli &> /dev/null; then
# Install sentry-cli
curl -sL https://sentry.io/get-cli/ | sh
else
echo "sentry-cli is already installed"
fi
- name: Upload dSYMs files to Sentry
run: |
sentry-cli debug-files upload --auth-token ${{ secrets.SENTRY_AUTH_TOKEN }} \
--include-sources \
$GITHUB_WORKSPACE/$APP_NAME.xcarchive/dSYMs
- name: Create IPA file
env:
EXPORT_OPTIONS_PLIST: ${{ secrets.EXPORT_OPTIONS_PLIST_BASE64 }}
run: |
EXPORT_OPTIONS_PLIST_PATH=$RUNNER_TEMP/ExportOptions.plist
echo -n "$EXPORT_OPTIONS_PLIST" | base64 -d -o $EXPORT_OPTIONS_PLIST_PATH
xcodebuild -exportArchive -archivePath $GITHUB_WORKSPACE/$APP_NAME.xcarchive -exportPath $RUNNER_TEMP/build -exportOptionsPlist $EXPORT_OPTIONS_PLIST_PATH
mv "$RUNNER_TEMP/build/Falling Sky.ipa" $RUNNER_TEMP/build/$APP_NAME.ipa
- name: Upload to TestFlight
env:
API_KEY_BASE64: ${{ secrets.APPSTORE_API_PRIVATE_KEY }}
run: |
mkdir -p ./private_keys
echo -n "$API_KEY_BASE64" | base64 --decode -o "./private_keys/AuthKey_${{ secrets.APPSTORE_API_KEY_ID }}.p8"
xcrun altool --validate-app -f ${{ runner.temp }}/build/${{ env.APP_NAME }}.ipa -t ios --apiKey ${{ secrets.APPSTORE_API_KEY_ID }} --apiIssuer ${{ secrets.APPSTORE_ISSUER_ID }}
xcrun altool --upload-app -f ${{ runner.temp }}/build/${{ env.APP_NAME }}.ipa -t ios --apiKey ${{ secrets.APPSTORE_API_KEY_ID }} --apiIssuer ${{ secrets.APPSTORE_ISSUER_ID }}