iOS 캠프 [알쓸신잡: 성장하는 iOS 개발자 되기] 요약
- 2021.04.27 화요일 4시
- 강연자: 전수열
1. 테스트
- 모두가 중요하다고 생각은 하지만 모두가 하고있지는 않다
- 무엇을 테스트할 것인가
- End-to-End - ex: 전체 구매 과정
- Integration - ex: 상품 상세 화면
- Unit - ex: 상품 가격 뷰
- 작은단위인 Unit 테스트부터 해보기를 권장
테스트 하기 쉬운 것부터
- 가격 포맷터, 날짜 포맷터, Codable변환, String 익스텐션…
- 입력이 같다면 출력도 같음
- 사이드 이펙트가 없음
- 이런 것도 굳이 테스트를 작성해야 할까?
- 네. 익숙해지는 것이 중요하므로 많이 작성 해보는게 좋다
- 테스트는 지식의 영역이 아니라 숙달의 영역
- 테스트를 작성하다보면 요구사항이 명확해진다
테스트 첫 작성
func testPriceView() {
let view = PriceView(costPrice: 10000, price: 6000)
XCTAssertEqual(view.priceLabel.text, "[40%] 6,000원")
}
만약 원가가 정가와 같다면?
func testPriceView_whenDiscounted_displaysDiscountRateAndPrice() {
let view = PriceView(costPrice: 10000, price: 6000)
XCTAssertEqual(view.priceLabel.text, "[40%] 6,000원")
}
func testPriceView_whenNotDiscounted_displaysPriceOnly() {
let view = PriceView(costPrice: 3000, price: 3000)
XCTAssertEqual(view.priceLabel.text, "3,000원")
}
만약 할인율에 소숫점이 생긴다면?
func testPriceView_whenDiscounted_displaysRoundedDiscountRateAndPrice() {
let view = PriceView(costPrice: 11000, price: 7000)
XCTAssertEqual(view.priceLabel.text, "[36%] 6,000원") // 36.363636...
}
만약 정가가 0원이라면?
func testPriceView_whenPriceIsZero_displaysFree() {
let view = PriceView(costPrice: 10000, price: 0)
XCTAssertEqual(view.priceLabel.text, "무료")
}
이렇게 테스트를 작성해나가면 테스트 스펙이 곧 기능 명세가 된다
func testPriceView_whenNotDiscounted_displaysPriceOnly()
func testPriceView_whenDiscounted_displaysDiscountRateAndPrice()
func testPriceView_whenDiscounted_displaysRoundedDiscountRateAndPrice()
func testPriceView_whenPriceIsZero_displaysFree()
스펙을 더 명확하게 작성하고 싶다면 한글로 쓰기
func testPriceView__할인되지_않은_경우__가격만_표시합니다()
func testPriceView__할인된_경우__할인율과_가격을_표시합니다()
func testPriceView__할인된_경우__반올림된_할인율과_가격을_표시합니다()
func testPriceView__가격이_0인_경우__무료로_표시합니다()
테스트가 더 복잡해진다면?
- 네트워크 요쳥, 시스템 프레임워크, 서드파티 라이브러리…
- 입력이 같아도 출력이 다를 수 있다
- 사이드이팩트가 생긴다
테스트 대역 (Test double): 연기자의 대역배우 개념
- Dummy: 파라미터를 채우기 위해 필요한 개체
- ex: 프로필 뷰를 테스트할 때 넘기는 User 개체
- fake: 작동하긴 하지만 테스트만을 위해서 만들어진 구현체
- ex: 실제 키체인에 저장하지 않고 메모리에서만 관리하는 키체인
- Stub: 미리 지정한 결과를 반환할 수 있는 구현체
- ex: 미리 지정한 이미지 선택 겨과를 반환하는 UIImagePickerStub
- Spy: Stub에 더해서 함수 호출을 기록할 수 있는 구현체
- ex: 호출된 메서드를 기록하는 MFMailComposeViewControllerSpy
- Mock: 원하는 메서드가 의도한 대로 잘 호출되었는지를 검증할 수 있는 구현체
- ex: 의도한 메서드가 호출되지 않으면 실패시키는 무언가
의존성 주입 (Dependency Injection)
현재 위치에따라서 테스트를 통과할 수도, 아닐수도 있음
func testGPSViewController_whenLoaded_displaysMyLatitudeAndLongitude() {
// given
let viewController = GPSViewController()
// when
viewController.loadViewIfNeeded()
// then
XCTAssertEqual(viewController.latitudeLabel.text, "37.5093999")
XCTAssertEqual(viewController.longitudeLabel.text, "126.8855371")
}
의존성 주입하여 실제 현재위치가 아닌 테스트를 위한 위치값 지정
func testGPSViewController_whenLoaded_displaysMyLatitudeAndLongitude() {
// given
let locationManager = CLLocationManagerStub()
locationManager.stubbedLatitude = 37.5740381
locationManager.stubbedLongitude = 126.9745863
let viewController = GPSViewController(locationManager: locationManager)
// when
viewController.loadViewIfNeeded()
// then
XCTAssertEqual(viewController.latitudeLabel.text, "37.5740381")
XCTAssertEqual(viewController.longitudeLabel.text, "126.9745863")
}
TDD
- 아래 싸이클 반복
- 실패하는 테스트부터 작성
- 테스트를 통과하는 최소한의 구현 작성
- 지저분한 구현 개선
- 리팩토링의 진짜 의미
- 실패하는 테스트가 존재
- 테스트를 통과하는 최소한의 구현이 존재
- 다시 작성하는 것이 아님(다시 작성하는건 재작성)
- 설계 변경 없이 구현만 개선하는 것! (테스트 코드는 변경되지 않음)
2. CI/CD 파이프라인
- 테스트 작성도 중요하지만, 테스트가 계속 실행되고 검증되는 것이 중요
- CI (Continuous Integration): 지속적 통합
- 개발-푸시-린트-빌드-테스트
- CD (Continuous Delivery): 지속적 배포
- 개발-푸시-빌드-배포
- 스테이징: 개발-푸시-빌드-배포(테스트플라이트)
- 프로덕션: 개발-푸시-빌드-배포(앱스토어)
- 사람이 할 일을 기계가 대신해줌으로서 사람은 더 중요한 일에 집중
3. 함께 성장하기
피드백 루프 만들기
- 주기적으로 유효한 피드백을 동료들과 나눌 수 있는 환경
- 행동 -> 피드백 -> 개선: 반복하며 성장
- 짝 프로그래밍 (실시간 피드백)
- 역할을 자주 바꾸는 것이 좋음
- 서로의 암묵지 꺼내기 (나는 당연하다고 생각하지만 상대방은 아닐 수 있음)
- 놓쳤다면 바로 질문하기
- 코드 리뷰 (작업 단위 피드백)
- 문제가 없는지 검증하는 것은 기본
- 배경이나 의사결정 등 맥락 전달
- PR 본문도 리뷰의 대상
- 좋은 PR은 리뷰어가 리뷰하기 좋은 PR
- 코딩 스타일은 웬만하면 기계가 하도록
- PR 템플릿
- 배경: 왜? 누가 요청?
- 작업 내용: 작성한 코드 요약
- 테스트 방법: 이 코드를 어떻게 테스트 할지
- 리뷰 노트: 리뷰어에게 주는 부가적인 정보
- 스크린샷(Before, After): 아카이빙에도 도움됨
- 회고 (이터레이션 단위 피드백)
- 탓하는 과정이 아니라 더 나아지기 위한 과정
- 감정에 더 솔직해지고 감정 상태를 더 많이 공유하기
- 왜 그런 감정을 느꼇는지에 대해서 집중적으로 회고해보는 것이 도움 됨
- 팀 회고
- 만족: 다음번에도 그대로 할 것들
- 반성: 다음번에는 다르게 할 것들
- 개선: 개선할 수 있을 것들
- 개인 회고
- Fact: 무엇을 했고
- Feeling: 무엇을 느꼇고
- Finding: 어떤 교훈이 있었다
질문 답변
- CI/C툴로 무엇을 사용하는지?
- GitHub Actions 사용이 가장 편했음
- 짝 프로그래밍은 어떤 경우에 하는지? 실제 업무에도 하는지
- 극단적으로 모든 커밋을 짝프로그래밍으로 하는 회사도 있음
- 새로운 멤버가 온보딩 했을 때
- 어떤 도메인을 잘아는 멤버가 있고 그걸 배우고 싶을 때
- 더 많이 알고 있는 사람이 작성을하는 것이 지켜보는 사람이 배울 수 있는 것 같음
- 신입을 뽑을 때 중요하게 보는 것
- 개발 자체를 즐거워 하는 것이 느껴짐
- 다야한 프로젝트를 도전해보고, 코드를 공개하고, 잘 정리한 모습
- 오픈소스 컨트리뷰트를 해보고 싶은데 어떻게 시도해볼지/?
- 문서의 오탈자를 찾아보는것 부터 시작해봐도 좋음
- 문서의 한글 번역이 없다면 한글 번역을 해본다던가
Leave a comment