iOS 주니어 테스트 및 코드품질 기술면접
새 면접Q. iOS에서 XCTest 프레임워크를 사용할 때, 테스트 메서드는 어떤 규칙으로 작성해야 하며, setUp()과 tearDown() 메서드의 역할은 무엇인가요?
테스트 메서드의 명명 규칙과 각 테스트 실행 전후에 필요한 준비 및 정리 작업을 생각해보세요.
XCTest에서 테스트 메서드는 반드시 'test'로 시작하는 이름을 가져야 하며, 반환 타입은 없고 매개변수도 받지 않습니다. setUp() 메서드는 각 테스트 메서드가 실행되기 전에 호출되어 테스트에 필요한 객체를 초기화하거나 공통 설정을 수행합니다. tearDown() 메서드는 각 테스트가 완료된 후 호출되어 리소스를 정리하고 메모리를 해제하는 역할을 합니다. 이를 통해 각 테스트가 독립적으로 실행되고 서로 영향을 주지 않도록 보장합니다.
- • 테스트 메서드는 'test' 접두사로 시작해야 함
- • setUp()은 테스트 전 초기화 작업 수행
- • tearDown()은 테스트 후 정리 작업 수행
- • 각 테스트의 독립성 보장
네트워크 매니저나 데이터베이스를 테스트할 때 setUp에서 mock 객체를 생성하고 tearDown에서 정리하여 테스트 간 간섭을 방지합니다.
setUpWithError()와 tearDownWithError()는 일반 setUp/tearDown과 어떤 차이가 있나요?
Q. 좋은 단위 테스트가 갖춰야 할 FIRST 원칙에 대해 설명해주세요.
Fast, Independent, Repeatable, Self-validating, Timely 각 항목이 의미하는 바를 생각해보세요.
FIRST 원칙은 Fast(빠른 실행), Independent(독립성), Repeatable(반복 가능성), Self-validating(자가 검증), Timely(적시성)를 의미합니다. Fast는 테스트가 빠르게 실행되어 자주 돌릴 수 있어야 함을 뜻하고, Independent는 테스트 간 의존성이 없어 순서에 관계없이 실행 가능해야 합니다. Repeatable은 어떤 환경에서도 동일한 결과를 보장해야 하며, Self-validating은 성공/실패를 명확히 판단할 수 있어야 합니다. Timely는 프로덕션 코드 작성과 동시에 또는 그 전에 테스트를 작성해야 함을 의미합니다.
- • Fast: 빠른 실행 속도
- • Independent: 테스트 간 독립성
- • Repeatable: 환경에 관계없이 동일한 결과
- • Self-validating: 명확한 성공/실패 판정
- • Timely: 적시에 테스트 작성
CI/CD 파이프라인에서 수백 개의 테스트를 빠르게 실행하고 신뢰할 수 있는 결과를 얻기 위해 FIRST 원칙을 준수합니다.
실무에서 FIRST 원칙 중 가장 지키기 어려운 것은 무엇이며, 어떻게 해결할 수 있을까요?
Q. iOS 테스트에서 Mock 객체와 Stub 객체의 차이점은 무엇이며, 각각 어떤 상황에서 사용하나요?
테스트의 목적이 행위 검증인지 상태 검증인지에 따라 선택이 달라집니다.
Stub은 테스트 중 호출되는 메서드에 대해 미리 정의된 값을 반환하는 객체로, 주로 상태 검증에 사용됩니다. Mock은 호출된 메서드, 호출 횟수, 전달된 파라미터 등을 검증하는 객체로 행위 검증에 사용됩니다. 예를 들어 네트워크 응답을 시뮬레이션할 때는 Stub을 사용하여 특정 데이터를 반환하고, API가 정확히 한 번 호출되었는지 검증할 때는 Mock을 사용합니다. iOS에서는 프로토콜을 활용해 Mock/Stub을 구현하거나, 서드파티 라이브러리를 활용할 수 있습니다.
- • Stub: 미리 정의된 값 반환, 상태 검증
- • Mock: 호출 행위 검증, 메서드 호출 추적
- • 네트워크/DB 등 외부 의존성 대체
- • 프로토콜 기반 구현
서버 API를 호출하는 코드를 테스트할 때 실제 서버 없이도 다양한 응답 시나리오를 Stub으로 시뮬레이션하여 테스트합니다.
Dependency Injection을 사용하면 테스트 작성이 어떻게 쉬워지나요?
Q. TDD(Test-Driven Development)의 Red-Green-Refactor 사이클에 대해 설명하고, 각 단계에서 무엇을 해야 하는지 말씀해주세요.
실패하는 테스트 작성, 테스트 통과시키기, 코드 개선의 순서로 진행됩니다.
Red 단계에서는 먼저 실패하는 테스트를 작성합니다. 구현하려는 기능의 요구사항을 테스트 코드로 표현하며, 아직 구현이 없으므로 테스트는 실패합니다. Green 단계에서는 테스트를 통과시키기 위한 최소한의 코드를 작성합니다. 이 단계에서는 코드 품질보다 테스트 통과에 집중합니다. Refactor 단계에서는 테스트가 통과하는 상태를 유지하면서 코드를 개선합니다. 중복 제거, 명확한 네이밍, 설계 개선 등을 수행하며, 이 과정에서 테스트가 안전망 역할을 합니다.
- • Red: 실패하는 테스트 먼저 작성
- • Green: 테스트 통과를 위한 최소 구현
- • Refactor: 테스트 통과 유지하며 코드 개선
- • 테스트가 안전망 역할 수행
새로운 비즈니스 로직을 구현할 때 TDD를 적용하면 요구사항을 명확히 하고 버그를 사전에 방지할 수 있습니다.
TDD를 적용하기 어려운 상황이나 코드 유형에는 어떤 것들이 있나요?
Q. iOS 프로젝트에서 리팩토링을 수행할 때 주의해야 할 점과, 리팩토링을 안전하게 진행하기 위한 전제 조건은 무엇인가요?
리팩토링은 외부 동작을 변경하지 않으면서 내부 구조를 개선하는 작업이며, 이를 보장하는 장치가 필요합니다.
리팩토링의 가장 중요한 전제 조건은 충분한 테스트 코드가 존재해야 한다는 것입니다. 테스트가 있어야 리팩토링 후에도 기능이 정상 동작하는지 확인할 수 있습니다. 리팩토링은 한 번에 하나의 작은 변경만 수행하고 매번 테스트를 실행하여 검증해야 합니다. 외부 동작은 절대 변경하지 않으며, 오직 내부 구조만 개선합니다. 또한 리팩토링과 기능 추가를 동시에 하지 않고 분리해서 진행해야 하며, 버전 관리 시스템을 활용해 언제든 이전 상태로 돌아갈 수 있도록 합니다.
- • 충분한 테스트 코드 존재 필수
- • 작은 단위로 변경하고 매번 테스트
- • 외부 동작 변경 없이 내부 구조만 개선
- • 기능 추가와 리팩토링 분리
- • 버전 관리 시스템 활용
거대한 ViewController를 여러 개의 작은 컴포넌트로 분리할 때, 단위 테스트를 먼저 작성하고 점진적으로 리팩토링합니다.
레거시 코드에 테스트가 없는 경우, 어떻게 안전하게 리팩토링을 시작할 수 있을까요?
Q. 효과적인 코드 리뷰를 위해 리뷰어가 확인해야 할 주요 항목들은 무엇이며, 건설적인 피드백을 제공하는 방법은 무엇인가요?
코드의 정확성, 가독성, 테스트, 설계 등 여러 측면을 확인하며, 피드백은 구체적이고 존중하는 태도로 전달해야 합니다.
코드 리뷰에서는 먼저 코드가 요구사항을 정확히 구현했는지, 버그나 예외 처리가 누락되지 않았는지 확인합니다. 코드의 가독성, 네이밍, 일관성을 검토하고, 적절한 테스트 코드가 포함되어 있는지 확인합니다. 설계 원칙(SOLID 등)을 준수하는지, 불필요한 중복이나 복잡도는 없는지 살펴봅니다. 피드백을 제공할 때는 '이 코드는 나쁘다'가 아니라 '이렇게 변경하면 더 명확할 것 같습니다'처럼 구체적이고 건설적으로 표현하며, 좋은 부분도 함께 언급하여 긍정적인 분위기를 만듭니다.
- • 요구사항 구현 및 버그 확인
- • 가독성, 네이밍, 일관성 검토
- • 테스트 코드 포함 여부
- • 설계 원칙 준수 확인
- • 구체적이고 건설적인 피드백
Pull Request를 통해 팀원의 코드를 리뷰하면서 잠재적 버그를 발견하고, 더 나은 설계 방향을 제안하여 코드 품질을 향상시킵니다.
코드 리뷰에서 의견이 충돌할 때 어떻게 해결하는 것이 좋을까요?
Q. XCUITest를 사용한 UI 테스트와 단위 테스트의 차이점은 무엇이며, UI 테스트 작성 시 주의해야 할 점은 무엇인가요?
UI 테스트는 실제 사용자 관점에서 앱을 테스트하지만, 실행 속도와 안정성 측면에서 고려할 사항이 있습니다.
단위 테스트는 개별 함수나 클래스의 로직을 검증하는 반면, UI 테스트는 실제 사용자가 앱을 사용하는 것처럼 화면 요소를 터치하고 입력하여 전체 흐름을 검증합니다. UI 테스트는 실행 속도가 느리고 환경에 민감하므로, 핵심 사용자 시나리오에만 선별적으로 작성해야 합니다. Accessibility Identifier를 활용하여 UI 요소를 안정적으로 찾고, 비동기 작업에 대해서는 적절한 대기 시간(waitForExistence)을 설정해야 합니다. 또한 테스트 데이터를 준비하고 각 테스트가 독립적으로 실행되도록 초기 상태를 설정하는 것이 중요합니다.
- • UI 테스트는 사용자 관점의 전체 흐름 검증
- • 실행 속도가 느려 핵심 시나리오만 선별
- • Accessibility Identifier 활용
- • 비동기 작업에 대한 적절한 대기 처리
- • 테스트 간 독립성 유지
로그인부터 결제까지의 핵심 사용자 여정을 UI 테스트로 자동화하여 주요 기능의 정상 동작을 보장합니다.
UI 테스트가 자주 실패하는 flaky test 문제를 어떻게 해결할 수 있을까요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!