TDD 10

[단위 테스트] 데이터베이스 테스트

통합 테스트에서 중요한 의존성으로 취급되는 데이터베이스를 효과적으로 테스트하는 방법을 알아본다. 통합 테스트를 위한 데이터 베이스 준비 - 개발을 위한 데이터 스키마 관리 데이터베이스 스키마는 버전별로 항상 형상관리에 저장되어야 한다. - 데이터베이스 배포 방식 상태 기반 데이터 베이스 배포 방식 vs 마이그레이션 기반 데이터 베이스 배포 방식 상태 기반 방식 개발 내내 관리 되는 모델 데이터베이스가 존재. 배포 중 비교 도구가 스키마 차이를 인식하여 차이에 대한 업데이트를 운영 데이터베이스에 적용하기 위한 스크립트를 만들어낸다. 비교 도구는 불필요한 테이블을 삭제하고 새 테이블을 생성하고 컬럼명을 바꾸는 등 모델 데이터베이스와 동기화하는데 필요한 작업을 수행한다. 마이그레이션 기반 방식 데이터베이스 기..

[단위 테스트] 목 활용하기

테스트 대상 시스템과 외부 의존성간 상호작용을 검증하기 위해 사용되는 목 활용 모범 사례를 알아본다. CRM 예제에서 목의 사용 TEST(TestUserController, 통합_테스트_이메일_변경_사내도메인에서_외부도메인으로) { // given auto db = new Database(string("connection")); auto insertUser = User::CreateUser("user@mycorp.com", UserType::Employee); auto insertCompany = Company::CreateCompany("mycorp.com", 1); db->SaveUser(insertUser); db->SaveCompany(insertCompany); auto messageBusMoc..

[단위 테스트] 통합 테스트

통합 테스트 단위 테스트가 아닌 모든 테스트 ex) 여러 의존성을 걸친 로직을 테스트 하는 것 vs 단위 테스트 : 빠르게 수행되는 단일 동작 단위를 검증 좋은 통합 테스트는 높은 회귀 방지율과 훌륭한 리팩토링 내성을 가진다. 테스트 피라미드 단위 테스트로 갈 수록 테스트 개수가 많아야한다. 위로 갈수록 만드는 비용이 커지지만 잘 만든 테스트는 시스템 전체의 정확성을 보장한다. 빠른 실패 원칙과 통합 테스트 지난 테스트를 위한 리팩토링 예제의 마지막에서 변경될 이메일 주소가 같은 경우 이메일을 변경할 필요가 없으므로 이른 확인을 통해 Company 데이터 베이스 접근을 안하게 하는 로직으로 최적화 하였다. bool UserController::ChangeEmailV3(int userId, string n..

[단위 테스트] 단위 테스트 리팩토링

어떤 코드를 리팩토링 할 것인가? -> 어떤 코드가 중요한 지 파악한다. 복잡도 혹은 도메인 유의성 - 코드의 분기가 얼마나 많은가 - 프로젝트의 문제 도메인에 대해 얼마나 의미 있는가 협력자 수 - 클래스 또는 메서드가 가진 협력자 수 - 가변 의존성 혹은 외부 의존성 리팩토링 목표 지나치게 복잡한 코드를 리팩토링 하여 협력자수를 줄이거나 복잡도를 줄이는 방향으로 함 험블 객체 험블 객체 : 테스트 하기 어려운 부분을 험블 객체로 이동하여 의존성을 분리 -> 지나치게 어려운 코드를 만드는 의존성을 테스트 로직에서 제거해야함 -> 험블 객체라는 얇은 래퍼 클래스를 통해 의존성을 분리 함수형 아키텍처에서 코드 유형 분류 도메인 모델 및 알고리즘 : 함수형 코어 및 도메인 계층 컨트롤러 : 가변 셸 및 어플..

[단위 테스트] 단위 테스트 스타일

단위 테스트 스타일 출력 기반 테스트 상태 기반 테스트 통신 기반 테스트 출력 기반 스타일 테스트 대상 시스템 SUT에 입력을 넣고 생성되는 출력을 점검하는 방식 "함수형 프로그래밍" -> 사이드 이펙트가 없는 방식 상태 기반 스타일 작업이 완료된 이후 상태를 확인하여 검증하는 방식. SUT, 협력자 혹은 데이터 베이스나 파일 시스템과 같은 외부 의존성 등의 상태를 확인. 통신 기반 스타일 테스트 대상과 협력자간의 통신을 검증한다. 출력 기반 vs 상태 기반 vs 통신 기반 출력 기반이 가장 단순하고 유지 보수하기 쉽다. 구현 세부사항과 결합이 거의 없다. 상태 기반은 거짓 양성이 되기 쉽다. 테스트 코드와 제품 코드의 결합도가 높아지기 때문. 통신 기반 규모가 있고 복잡하여 유지 보수하기 어렵다. 출력..

[단위 테스트] 목과 테스트 취약성

Mock 목과 테스트 취약성 목과 스텁의 구분 - 테스트 대역 유형 테스트 대역 : 더미, 스텁, 스파이, 목, 페이크 목 : 외부로 나가는 상호작용을 모방하고 검사하는 것에 도움. SUT가 상태를 변경하기 위해 의존성을 호출. 스텁 : 내부로 들어오는 상호작용을 모방하는데 도움. SUT가 입력 데이터를 얻기 위한 의존성을 호출. ex) 이메일 발송 -> SMTP 서버 (목 : STMP 서버 상태를 변경) 데이터 검색 SUT가 갖는 의존성을 준비시키는 것이지, 의존성을 준비하는 것을 검증해야할 만큼 의미가 있는 행위가 아니다. -> 과잉 명세, 거짓 양성으로 이어지며 리팩토링 내성을 약화 시킨다. CQS Command Query Separation (명령 조회 분리) 모든 메서드는 명령이거나 조회이어야만..

[단위 테스트] 좋은 단위 테스트의 4대 요소

좋은 단위 테스트를 작성하기 위한 4대 요소 -> 회귀 방지 -> 리팩토링 내성 -> 빠른 피드백 -> 유지 보수성 회귀 방지 간단히 말해서 버그를 방지하는 테스트 코드를 작성하는 것이다. 회귀 방지는 코드의 복잡도, 전체 실행되는 코드 양, 도메인의 중요성에 따라 긴밀하게 작성되어야 한다. 리팩토링 내성 테스트 코드가 테스트하는 실제 로직을 리팩토링 했을 때, 테스트 결과가 빨간불이 나오면 안된다. 이는 테스트 코드의 품질과 높은 연관이 있다. - 거짓 양성 False Positive 거짓 양성으로 판별되는 테스트 코드는 실제 코드가 기능적으로 정상이지만 테스트 결과는 실패를 반환하는 것을 의미한다. "높은 회귀 방지율" 좋은 단위 테스트는 기능 고장이 실제 배포 전에 테스트를 통해 실패가 되어 미리 ..

[단위 테스트] 단위 테스트 구조

좋은 단위 테스트 작성하기 1. AAA 패턴 사용하기 - Given/When/Then으로 지칭하기도 한다. 2. 테스트 코드에서 if 문은 사용하지 말라 - 테스트에서 케이스가 생기는 if문 자체가 안티 패턴이다. 3. 준비 (Arrange) 구절 - 3가지 구절에서 보통 가장 길다. 적절한 디자인 패턴으로 리팩토링을 하여 코드 줄 수를 줄인다. 4. 실행 (Act) 구절 - 실행 구절이 한 줄 인 경우를 피하라. 두 줄 이상의 코드를 호출해야한다면 API 설계가 잘 못 된 것이다. 5. 검증 (Assert) 구절 - 적절한 객체 동등비교 equaltiy 논리를 구현하고 검증 구절을 간소화 한다. 6. 검증 대상 객체 (SUT) - SUT를 지칭하는 변수를 sut라고 작성하는 등 SUT를 구별한다. 테스..

[단위 테스트] 단위 테스트 정의와 활용

'단위 테스트' 정의 -> 작은 코드 조각을 검증하고 -> 빠르게 수행하고 -> 격리된 방식을 처리하는 자동화된 테스트 고전파 vs 런던파 런던파에서는 테스트 대상 시스템(SUT)를 협력자에게서 격리하는 것을 의미. 모든 협력자는 테스트 대역으로 대체. 쉽게 말해서 테스트 대상 객체가 아닌 다른 객체에 의해 테스트가 실패할 요인을 없애는 것. ex) 타이어(Tire) 객체에 의존하는 자동차(Car) 객체 class Tire { public: virtual void run() { } }; class Car { private: Tire tire; public: Car(Tire _tire) : tire(_tire) { } void run() { tire.run(); } }; 런던파에서는 Tire를 테스트 대역..

[단위 테스트] 단위 테스트란

단위 테스트의 목적 지속 가능한 소프트웨어 개발을 위한 방법. 테스트가 없는 소프트웨어 개발을 하다보면 오류에 취약하고 확장성이 없는 코드를 만들어 내기 시작하고 이것이 어느 순간 부터 버그를 눈덩이처럼 만들기 시작하면 버그를 수정하기 위한 시간을 더 많이 소비해 결국 실질 작업 속도를 잡아먹는 다는 이야기 좋은 테스트란? -> 기반 코드를 리팩토링하면서 테스트 코드도 신경쓰며 리팩토링하는 것 -> 각 코드 변경시 테스트를 실행 -> 테스트가 잘못된 경고를 발생시킬 경우 해결 -> 기본 코드가 어떻게 동작하고 이해하려고 할 때는 테스트를 읽는 데 투자 코드 커버리지 - 테스트가 커버하는 비지니스 로직의 비율은 얼마나 되는 가? - 비지니스 로직의 일부분중 테스트가 커버하는 부분이 없지는 않는 가? 테스트..