PostgreSQL 주니어 테스트·코드품질 면접
새 면접Q. PostgreSQL을 사용하는 애플리케이션에서 단위 테스트와 통합 테스트를 수행할 때, 각각 어떤 방식으로 데이터베이스를 다루어야 하나요? 실제 DB를 사용하는 것과 Mock/Stub을 사용하는 것의 장단점을 비교하여 설명해주세요.
단위 테스트는 격리성과 속도, 통합 테스트는 실제 동작 검증에 중점을 둡니다.
단위 테스트에서는 데이터베이스 로직을 Mock이나 Stub으로 대체하여 빠른 실행과 외부 의존성 제거를 추구합니다. 이를 통해 특정 비즈니스 로직만 격리하여 테스트할 수 있고, 테스트 속도가 빠르며 CI/CD 파이프라인에서 유리합니다. 반면 통합 테스트에서는 실제 PostgreSQL 인스턴스(테스트용 컨테이너나 별도 스키마)를 사용하여 쿼리, 트랜잭션, 제약조건 등이 실제로 동작하는지 검증합니다. Mock을 사용하면 빠르지만 실제 DB 동작과 차이가 발생할 수 있고, 실제 DB를 사용하면 신뢰도가 높지만 테스트 속도가 느리고 환경 설정이 복잡합니다. 실무에서는 단위 테스트는 Mock을, 통합 테스트는 Docker 기반 테스트 DB를 사용하는 것이 일반적입니다.
- • 단위 테스트는 Mock/Stub으로 DB 의존성 제거
- • 통합 테스트는 실제 PostgreSQL 인스턴스 사용
- • Mock은 빠르지만 실제 동작과 차이 발생 가능
- • 실무에서는 테스트 목적에 따라 전략 혼용
CI/CD 파이프라인에서 빠른 피드백을 위해 단위 테스트는 Mock으로, 배포 전 최종 검증은 실제 DB로 통합 테스트를 수행합니다.
테스트 환경에서 PostgreSQL 데이터베이스를 초기화하고 테스트 데이터를 준비하는 방법으로는 어떤 것들이 있나요?
Q. PostgreSQL 데이터베이스를 사용하는 테스트 코드에서 테스트 간 데이터 격리를 보장하기 위한 방법들을 설명해주세요. 특히 트랜잭션 롤백, 데이터베이스 초기화, 테스트 픽스처(Fixture)의 장단점을 비교해주세요.
각 테스트가 독립적으로 실행되려면 이전 테스트의 데이터가 영향을 주지 않아야 합니다.
트랜잭션 롤백 방식은 각 테스트를 트랜잭션 내에서 실행하고 테스트 종료 시 ROLLBACK하여 데이터를 원상복구하는 방법으로, 가장 빠르고 효율적이지만 트랜잭션 커밋을 테스트할 수 없다는 한계가 있습니다. 데이터베이스 초기화 방식은 매 테스트마다 테이블을 TRUNCATE하거나 DROP/CREATE하는 방법으로, 완전한 격리를 보장하지만 속도가 느립니다. 테스트 픽스처는 setUp 단계에서 필요한 데이터를 INSERT하고 tearDown에서 삭제하는 방식으로, 테스트에 필요한 데이터만 준비할 수 있지만 관리 코드가 복잡해질 수 있습니다. 실무에서는 트랜잭션 롤백을 기본으로 사용하고, 트랜잭션 동작 자체를 테스트해야 할 때만 데이터베이스 초기화를 사용합니다.
- • 트랜잭션 롤백은 빠르지만 커밋 동작 테스트 불가
- • 데이터베이스 초기화는 완전한 격리 보장하나 느림
- • 테스트 픽스처는 필요한 데이터만 준비 가능
- • 실무에서는 트랜잭션 롤백을 기본 전략으로 사용
통합 테스트 실행 시 각 테스트를 트랜잭션으로 감싸고 종료 후 롤백하여 테스트 간 데이터 간섭을 방지합니다.
여러 테스트에서 공통으로 사용하는 기본 데이터(예: 카테고리, 설정값)는 어떻게 관리하는 것이 효율적일까요?
Q. 복잡한 PostgreSQL 쿼리(여러 JOIN, 서브쿼리, 집계 함수 포함)의 정확성을 검증하는 테스트 코드를 작성할 때 고려해야 할 사항과 테스트 케이스 설계 방법을 설명해주세요. 경계값 테스트와 NULL 처리는 어떻게 검증하나요?
쿼리 결과의 정확성뿐만 아니라 예외 상황도 테스트해야 합니다.
복잡한 쿼리를 테스트할 때는 먼저 예상 결과를 명확히 정의한 테스트 데이터를 준비해야 합니다. 정상 케이스뿐만 아니라 빈 결과, 단일 행, 다중 행, 중복 데이터 등 다양한 시나리오를 포함해야 합니다. 경계값 테스트는 0, 음수, 최대값, 날짜 범위의 시작/종료 등을 테스트 데이터에 포함시켜 WHERE 조건과 집계 함수가 올바르게 동작하는지 검증합니다. NULL 처리는 JOIN 대상 컬럼이나 집계 대상 컬럼에 NULL 값을 포함한 테스트 데이터를 준비하고, LEFT JOIN의 결과나 COUNT/SUM의 NULL 처리가 예상대로 동작하는지 확인합니다. 테스트 코드에서는 실제 쿼리 실행 결과와 기대값을 행 수, 특정 컬럼 값, 정렬 순서 등 여러 측면에서 비교하여 검증합니다.
- • 다양한 시나리오(빈 결과, 단일/다중 행, 중복)를 테스트 케이스에 포함
- • 경계값(0, 음수, 최대값, 날짜 범위)을 테스트 데이터에 포함
- • NULL 값을 포함한 데이터로 JOIN과 집계 함수 동작 검증
- • 결과의 행 수, 값, 정렬 순서를 다각도로 검증
매출 집계 쿼리를 테스트할 때 0원 주문, NULL 할인율, 월말 경계 날짜 등을 테스트 데이터에 포함하여 예외 상황을 검증합니다.
쿼리 성능 테스트는 어떻게 수행할 수 있으며, 성능 저하를 감지하기 위한 방법은 무엇인가요?
Q. PostgreSQL 데이터베이스 스키마를 변경(컬럼 추가, 타입 변경, 테이블 분리 등)할 때 안전하게 리팩토링하기 위한 전략을 설명해주세요. 마이그레이션 스크립트 작성 시 주의사항과 롤백 계획은 어떻게 수립하나요?
운영 중인 데이터베이스는 무중단으로 변경해야 하며, 문제 발생 시 되돌릴 수 있어야 합니다.
데이터베이스 스키마 리팩토링은 먼저 개발 환경에서 충분히 테스트한 후 단계적으로 적용해야 합니다. 마이그레이션 스크립트는 UP(변경 적용)과 DOWN(롤백) 두 가지를 모두 작성하여 문제 발생 시 즉시 되돌릴 수 있어야 합니다. 컬럼 추가 시에는 NULL 허용 또는 DEFAULT 값을 설정하여 기존 데이터에 영향을 주지 않도록 하고, 타입 변경은 호환되지 않는 경우 새 컬럼을 추가한 후 데이터 마이그레이션을 거쳐 기존 컬럼을 삭제하는 다단계 접근을 사용합니다. 테이블 분리는 애플리케이션 코드가 양쪽 구조를 모두 지원하도록 수정한 후 데이터를 이관하고 기존 테이블을 제거하는 순서로 진행합니다. 모든 변경은 트랜잭션 내에서 수행하고, 운영 환경 적용 전에 백업을 필수로 수행해야 합니다.
- • UP/DOWN 마이그레이션 스크립트를 모두 작성
- • 컬럼 추가는 NULL 허용 또는 DEFAULT 값 설정
- • 타입 변경은 새 컬럼 추가 후 데이터 마이그레이션하는 다단계 접근
- • 변경 전 백업 필수, 트랜잭션 내에서 실행
사용자 테이블의 전화번호 컬럼을 VARCHAR(20)에서 VARCHAR(50)으로 변경할 때 롤백 스크립트를 함께 준비하고 트랜잭션으로 실행합니다.
대용량 테이블에서 컬럼 타입을 변경할 때 락(Lock)을 최소화하는 방법은 무엇인가요?
Q. PostgreSQL 쿼리나 데이터베이스 관련 코드를 리뷰할 때 확인해야 할 주요 체크리스트를 설명해주세요. 특히 성능, 보안, 유지보수성 측면에서 어떤 점들을 중점적으로 검토해야 하나요?
쿼리의 효율성, SQL 인젝션 위험, 가독성 등 여러 측면을 고려해야 합니다.
성능 측면에서는 인덱스 활용 여부, N+1 쿼리 문제, 불필요한 SELECT * 사용, JOIN 순서와 조건, 서브쿼리 최적화 가능성을 확인해야 합니다. 보안 측면에서는 SQL 인젝션 취약점이 있는지 확인하고, 파라미터 바인딩이나 Prepared Statement를 사용하는지 검토합니다. 유지보수성 측면에서는 쿼리의 가독성, 매직 넘버나 하드코딩된 값 사용 여부, 주석 유무, 트랜잭션 범위의 적절성을 점검합니다. 또한 NULL 처리가 명확한지, 제약조건과 외래키가 적절히 설정되어 있는지, 롤백 가능성을 고려했는지도 확인합니다. 코드 리뷰 시에는 EXPLAIN ANALYZE로 실행 계획을 확인하고, 테스트 코드가 함께 작성되었는지도 검토해야 합니다.
- • 성능: 인덱스 활용, N+1 문제, SELECT * 지양
- • 보안: SQL 인젝션 방지, 파라미터 바인딩 사용
- • 유지보수성: 가독성, 트랜잭션 범위, NULL 처리
- • 테스트 코드와 실행 계획 검토 필수
Pull Request에서 ORM 쿼리를 검토할 때 N+1 문제가 있는지 확인하고, 적절한 Eager Loading이나 JOIN을 제안합니다.
동료가 작성한 쿼리에서 성능 문제를 발견했을 때, 어떤 방식으로 피드백을 제공하는 것이 효과적일까요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!