session 1 단위테스트...
TRANSCRIPT
2014년 5월죽기 전에 테스트할 것인가,죽고 나서 테스트할 것인가!
단위 테스트, 그는 적인가 아군인가?
- SimpleSoft 유경상 수석 컨설턴트
Session 1
시작하기 앞서…
• 단위 테스트(Unit Test)란?• 정의
• 컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차 (출처: 위키백과)
• 주체• 개발자
• 테스터
• 대상• 프로그램 소스 코드
• 단위 테스트는 개발자의 적인가 아군인가?
피아 식별
• 개발자의 적들• 다양한 기술적, 인적 적대 관계
• 빠른 기술의 변화, xx한 관리자, xx한 고객, ……
• 자기 자신
• 프로젝트 수행 상의 적대 관계• 부실한 설계, 짧은 개발 일정, 잦은 요구사항 변경, ……
• 주 적• 버그
• 개발자의 우방• 개발도구(Visual Studio !)
• ……
좀 이른 결론(?)
• 단위 테스트는 코드가 의도한 대로 작동하는 지 검사해 준다.
• 코드가 의도한 대로 작동하지 않는 것은 버그 이다.
• 버그는 개발자의 주적이다.
• 따라서…개발자의 주적인 버그를 찾는데 도움이 되는 단위테스트는 아군이다!
그러나…
• 어제의 아군이 오늘의 적이 될 수도 있다!• 짧은 개발 환경에서 단위 테스트를 작성할 여유가 있는가?
• UI를 갖는 코드는 테스트 코드 작성이 어렵다.
• ……
• 정말 단위 테스트는 아군인가?
단위 테스트의 시작
• 단위 테스트는 코드 조각 혹은 일정 모듈을 테스트하는 코드
• 어렵지 않아요!• 간단한 단위 테스트
• DLL 코드의 일부를 테스트하는 콘솔 어플리케이션
• 서버 일부 기능을 테스트하기 위한 간단한 웹 페이지
• 기타
• 개발자의 대부분은 이미 단위 테스트에 대한 경험을가지고 있음
단위 테스트 도구
• 도구가 필요한 이유• 테스트 코드가 많아 짐에 따라 수작업으로 테스트 코
드 관리가 어려워 짐
• 테스트 결과에 대한 수집이 어려움
• 개발팀이 공유할 수 있는 자동화된 테스트 필요
• 단위 테스트 프레임워크• Visual Studio Unit Test Framework (MSTest)
• xUnit• 오픈 소스 단위 테스트 프레임워크의 일반적인 명칭
• Nunit, xUnit.net, ……
• 상용 제품들
단위 테스트의 재시작
• 가장 간단한 단위 테스트 – Smoke Test• 유래 – 하드웨어 작성 이후 전원을 넣어 칩이 타지 않는지 확인하는
테스트
• 가장 간단한 단위 테스트로서 작성한 코드를 호출해 보고 예외 발생여부만을 테스트
• 결과값에 대한 확인 등의 복잡(?)한 작업은 수행하지 않음
• Tip• 가장 많이 사용되는 코드 패턴 사용
• 메서드 오버로드, 매개변수, 호출 방식
• 수행 결과 출력• 수동으로 결과 확인 가능
초큼 발전된 단위 테스트
• 테스트 대상이 의도 대로 작동하는지 테스트• 주어진 입력(값)에 대해 의도한 작동(결과값)을 수행하는지
확인
• 초급 단위 테스트• 미리 정의된(계획된) 입력에 대해 의도한 결과가 나오는지
확인• Assertion 활용
• Tip• 입력값 및 예상 결과 값을 하드 코드 하지 않을 것• 당연한 결과에 대해서도 의심할 것• Assert 클래스의 다양한 메서드를 활용할 것
Go? Stop?
• 단위 테스트는 어느 정도까지 만드는 것이 좋은가?• 무한정 단위 테스트를 작성할 수는 없다.
• 가능한 모든 시나리오를 단위 테스트화 할 수 없다.
• 작성한 단위 테스트로 테스트되지 않는 코드를 파악해야 한다.
• Code Coverage Analysis• 테스트 코드에 의해 테스트된 코드를 파악하여 시각적으로, 수치적으
로 표현
• 테스트되지 않은 코드들 파악
• 추가적으로 작성해야 할 단위 테스트 파악
Code Coverage
• 일정 수준 단위 테스트 수행 후 Code Coverage 분석 수행• 테스트 되지 않은 코드 파악• 추가 단위 테스트 작성 및 테스트• 다시 Code Coverage 분석 수행• …… 반복 ……
• Tip• 개발이 어느 정도 완료된 이후 Coverage Test 수행• 일정 목표 수준까지 단위 테스트 및 Code Coverage 반복
• 단위 테스트를 처음 도입하는 경우 30% 정도를 목표로 단위 테스트 작성• 추후 60 ~ 70% 수준까지 단위 테스트 작성
• 예외/오류 상황에 대한 코드가 테스트 되지 않는 경우가 많음
오류 상황에 대한 단위 테스트
• 오류 상황에서 적절한 예외가 발생하는지 테스트• 오류를 유발하도록 상황 구성
• try ~ catch를 사용하여 예상되는 예외가 발생하는지 확인• 예외가 발생하지 않는 경우 Assert.Fail 호출(테스트 실패)
• ExpectedExceptionAttribute 활용
• Tip• 정상적으로 발생될 것으로 기대되는 예외(들)만을 catch 할 것
• Exception 클래스를 catch 하는 것은 테스트의 의미가 없음
• 오류 유발을 위한 도구(Mocking, Faking, …..) 활용
고급 단위 테스트
• 시나리오 구성• 다양한 조건을 구성하여 코드가 정상적으로 작동하는지 테스트
• 각 조건 별로 단위 테스트 작성
• 특정 조건(시간, 이벤트 등)에 수행되는 코드를 테스트 하기 위해 해당조건이 유발되도록 테스트 코드 작성• Ex) 파일 변경 – 실제로 파일을 변경하는 테스트 코드 작성
• 복잡한 검증 코드가 필요할 수도 있음
• 시간, 이벤트 등 다수의 조건들은 단위 테스트 상에서 유발시키기 어려움• Ex) 날짜 변경시 어떠한 작업을 수행해야 하는 경우
Fakes Framework - 소개
• Stub 및 Shim을 사용하여 테스트 대상 코드를 다른 모듈과 격리시킬 수 있음• 미 구현 모듈이나 특정 상황 에뮬레이션 가능
• Stub : 특정 인터페이스의 구현을 다르게 대체 (mock object)
• Shim : 컴파일 된 코드의 특정 메서드를 대체
• Visual Studio Premium/Ultimate에서 사용 가능
Fakes Framework - 사용법
• 단위 테스트 프로젝트에서 대상 어셈블리 선택 후 Fake 어셈블리 추가• Fake 어셈블리 자동 생성 및 참조가 추가됨
• Stub 클래스 및 Shim 클래스는 별도의 *.Fakes 네임스페이스에 생성됨
IDataRepository db = new Fakes.StubIDataRepository();
db.SaveOrderInt32Int32 = (pid, amt) => 99;
using (var ctx = ShimsContext.Create())
{
ShimBillingManager.AllInstances.CardApprovalStringInt32 =
(org, info, amount) => true;
var bizLogic = new BizLogic(db);
bizLogic.PlaceOrder(1, "CARD", 1000);
}
Fakes Framework – 고려 사항
• 제약• Stub
• 인터페이스 메서드들(virtual methods)에 대해서만 메서드 치환 가능• 테스트 코드에서 접근 가능한 타입들(public 및 internal)에 대해 적용 가능
• Shim• static, non-virtual 멤버 및 sealed 멤버들에 대해서 적용 가능• public, internal 및 일부 private 메서드들에 대해 적용 가능• 메서드 본문(body)가 없는 메서드들(interface, abstract method) 적용 불
가
• http://msdn.microsoft.com/en-us/library/hh549175.aspx 참고
• 성능• Shim은 런타임에 코드가 생성되므로 느림. Stub은 성능 저하 거의
없음
Fakes Framework - 활용
• 코드 격리• 미 구현된 코드 혹은 테스트 범위가 아닌 코드를 테스트
대상 코드와 격리• Ex) 비즈니스 로직 테스트를 위해 데이터 조회 코드를 Stub/Shim
으로 에뮬레이션
• 항상 고정된 값을 반환하도록 Stub/Shim으로 에뮬레이션• Ex) 날짜에 의존적인 코드 : DateTime.Now가 항상 같은 값을 반환
하도록 변경
• 테스트 상황 구성• Stub/Shim을 이용하여 특정 상황 에뮬레이션 가능
• Ex) 오류 상황을 에뮬레이션 하기 위해 코드의 반환값 변경
Native Code 단위 테스트
• VS2012 부터 Native Code 단위 테스트 지원• Native Code 테스트 프로젝트 템플릿• C++ 기반 단위 테스트 지원• 다양한 모듈에 대한 단위 테스트 가능
• Dynamic Library(.dll)• Static Library(.lib)• Compiled object file (.obj)• Executables (.exe)
• CppUnitTest.h• 단위 테스트를 위한 매크로, 함수 정의• 다양한 Assertion 함수들• 로깅 함수들
• http://msdn.microsoft.com/en-us/library/hh419385.aspx 참조
단위 테스트 활용예
• 단위 테스트 기반 디버깅1. 버그 리포트 검토
2. 버그를 재현하는 단위 테스트 작성
3. 단위 테스트 실패 확인
4. 버그 수정
5. If (단위 테스트 == Failure) goto 4
6. 버그 수정 완료
단위 테스트 주요 팁• 점진적인 단위 테스트 도입
• 테스트 대상 코드 격리 (Fakes Framework)
• Code Coverage 적극 활용
• 단위 테스트를 위한 원본 코드 변경 금지• 테스트 어셈블리에 대해 InternalsVisibleToAttribute 적용
• Internal 타입/멤버 테스트 용이
• PrivateObject 클래스 활용• Reflection보다 쉽게 Private 멤버 접근 가능
• 단위 테스트 수행 범위 조정 (필터 활용)• 단위 테스트 명명 기법 활용• Run Tests After Builds 기능 활용
• ALM 연계• TFS Build System – 빌드 후 단위 테스트 실패 시 빌드 실패로 처리 가능
단위 테스트 기반 개발 절차
while (목표 기능/모듈 개발 완료 == false) {
코드 작성;
while(Coverage < 목표 Coverage) {
단위 테스트(들) 작성;
작성한 단위 테스트(들) 수행;
while (단위 테스트 결과 == failure) {
코드 디버깅 및 수정; // 단위 테스트 코드 포함
}
}
}
전체 단위 테스트 수행;
if (전체 단위 테스트 결과 == failure) {
코드 디버깅 및 수정;
}
단위 테스트 도입 효과
• 조기에 버그 발견 가능• Smoke Test 만으로도 버그 발견 가능
• 코드에 대한 자신감(품질 향상)• 코드 변경이 미치는 영향 파악 가능
• 일정 수준 이상의 Coverage 필요
• 코드 변경에 따른 다른 모듈의 영향 파악이 쉬움• 나의 코드 변경이 다른 단위 테스트의 실패를 유도한다면 잘못된 코드
변경일 가능성이 높음
• 동시 개발이 용이함• 의존성을 갖는 다른 모듈의 완성을 기다릴 필요 없이 테스트 가능
단위 테스트의 부작용
• 개발 기간 부담이 늘어남• SI 프로젝트에서 적용하기 쉽지 않음
• 테스트 환경 꾸미기가 쉽지 않은 상황이 많음• 단위 테스트는 매우 자주 반복되므로 고정된 입력에 고정된 결과가 나
와야 함
• 데이터베이스 기반 코드들은 시간이 흘러감에 따라 다른 조회 결과가나올 가능성이 높음
• UI에 대한 단위 테스트가 쉽지 않음• Coded-UI Test로 부분적인 커버 가능
• 버그를 가진 단위 테스트
제안 사항
• Solution/Product S/W• 개발 초기부터 단위 테스트를 작성하고 유지
• UI에 대한 단위 테스트 포함
• Coverage 70% 이상 유지
• SI Project• 서버 모듈들에 대해서라도 단위 테스트 작성 및 유지
• 유지보수에 단위 테스트가 큰 도움이 될 수 있음(개발은 짧고 유지보수는 길다!)
결론
• 단위 테스트는 아군인가 적인가?• 단기적으로 개발자의 부담이 증가하지만,
• 장기적으로 개발자의 부담을 줄여줌.
• 버그를 줄여주며,
• 코드 품질을 향상시켜줄 수 있으므로,
• 단언컨데, 단위 테스트는 개발자의 든든한 우방임.
• 개발 초기부터 조금씩 단위 테스트 작성
• 단위 테스트 관련 도구들 적극 활용