Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

테스터가 말하는 테스트코드 작성 팁과 사례

5,837 views

Published on

좋은 테스트와 테스트코드에 대해 실제 프로젝트에서 개선하면서 겪었던 사례 기반으로 설명해 봤습니다.

Published in: Software

테스터가 말하는 테스트코드 작성 팁과 사례

  1. 1. 사례기반 (Junit) 테스트케이스 작성 팁 2011.01 by JungGun home: genycho.blog.me ※ 상업적 이용 및 출처를 밝히지 않은 무단 사용을 금합니다
  2. 2. What… 테스트를 하는 사람 입장에서 좋은 테스트와 테스트코드를 말하기 위함 현장에서 경험했던 사례를 예로 들어, 특정 개발언어, 단위테스트에만 적용되는게 아니라 모든 테스트 코드에 적용될 수 있는 내용
  3. 3. 좋은 테스트와 테스트 코드? 당신의당신의당신의당신의 테스트테스트테스트테스트 코드는코드는코드는코드는 안녕하십니까안녕하십니까안녕하십니까안녕하십니까???? 작성한작성한작성한작성한 테스트가테스트가테스트가테스트가 모두모두모두모두 성공하는데성공하는데성공하는데성공하는데 그럼그럼그럼그럼 테스트를테스트를테스트를테스트를 잘잘잘잘 한한한한 걸까걸까걸까걸까???? 테스트테스트테스트테스트 커버리지커버리지커버리지커버리지가가가가 80%80%80%80% 넘게넘게넘게넘게 나왔는데나왔는데나왔는데나왔는데 그럼그럼그럼그럼 테스트를테스트를테스트를테스트를 잘잘잘잘 한한한한 걸까걸까걸까걸까????
  4. 4. 테스트 (코드) 작성 팁 1. 요구사항을 명확하고 온전하게 이해하라 2. 테스트 케이스 ID는 의미있고 쉽게 이해가능해야 한다 3. 하나의 테스트 케이스에서는 하나의 흐름만을 테스트 하도록 해라 4. 결함은 경계에 서식한다. 5. 테스트의 목적과 한계를 명확히 이해하고 테스트 케이스를 작성하라. 6. 테스트 케이스를 통해 제품이 어떻게 동작하는지를 서술하라. 7. 누구나 이해 가능하도록 쉬운 테스트 코드를 유지하라 8. 테스트 코드 자체만으로 어떤 내용을 테스트 하려는지 표현하라 9. 작은 변경에 대해서도 이 변경을 알려 줄 수 있는 테스트 코드를 작성하라 10. 에러 발견시 발생 위치, 대략적 원인을 제공해 줄 수 있도록 테스트 코드를 작성하라. 11. 테스트 결과는 사람이 아닌 코드가 검증하도록 하라 12. assert문을 제대로 이해하고 강화하라 13. 단순히 코드를 반복하지 않기 위하여 테스트 라이브러리를 만들지 마라. 14. 테스트 외부와 내부를 구분하라
  5. 5. 1. 요구사항을 명확하고 온전하게 이해하라 테스트해야 하는 정황을 이해하고 테스트 요건을 도출한다 테스트 요건이 분석되면 다양한 접근법으로 테스트 케이스를 도출할 수 있다 사례) 테스트 요건 등을 테스트 코드의 주석으로 작성하면서 테스트 하려는 바와 테스트를 하는 방법에 대해 고민할 수 있다 테스트 케이스 설명
  6. 6. 2. 테스트 케이스 ID는 의미있고 쉽게 이해할 수 있어야 한다 테스트 코드는 계속 수행된다. 나중에 보더라도 이 테스트가 무엇이고 무슨 의도를 갖고 있는지 바로 파악할 수 있어야 한다 사례) 의미없는 숫자 시퀀스보다는 의미있는 이름으로 수정한다 testGetNewLandmarkList_0208_07 -> testGetNewLandmarkList_invalidFilterType 사례) 코드 상의 테스트케이스 명을 한글로 작성할 수도 있다 test_잘못된아이디로로그인시도하는경우
  7. 7. 3. 하나의 테스트 케이스에서는 하나의 흐름만을 테스트 하도록 해라 하나의 테스트 케이스에 검증문(assert)이 1개여야 한다는 말이 아니다 검증하려는 의도(목적)가 1개여야 테스트가 실패했을 때 직관적으로 문제상황을 이해하고 원인을 유추할 수 있다 TC1 TC2 TC3 AAAAAAAA 테스트테스트테스트테스트 :::: 1)1)1)1) 테스트테스트테스트테스트 시작시작시작시작 2)2)2)2) 가에가에가에가에 대한대한대한대한 결과결과결과결과 확인확인확인확인 3)3)3)3) 다시다시다시다시 테스트테스트테스트테스트 4)4)4)4) 나에나에나에나에 대한대한대한대한 결과결과결과결과 확인확인확인확인 5)5)5)5) 다시다시다시다시 테스트테스트테스트테스트 6)6)6)6) 다에다에다에다에 대한대한대한대한 결과결과결과결과 확인확인확인확인 7)7)7)7) 테스트테스트테스트테스트 종료종료종료종료
  8. 8. 4. 결함은 경계에 서식한다 문자 : null, 빈 문자, 공백문자, 허용 자릿수보다 긴 문자열, 예약어, 다국어 숫자 : 음수, 0, 하한값 -1, 상한값 +1, 숫자가 아닌 표시, + 기호로 시작하는 값 코드값 : 유효하지 않은 코드값 위,경도값 : 90.도 180.도 이상 이하의 값 페이지값 : 존재하지 않는 페이지 날짜 : 유효하지 않은 년,월,일, 날짜 포멧에 어긋나는 날짜값, 디스카운트 % : 음수 %값, 100% 이상 …… 0 100 다양한 테스트 기법을 알아두면 테스트를 더 잘 할 수 있다 예) 상황에 따라 경계값 분석, 동등 분할 등
  9. 9. 5. 테스트의 레벨에 따른 목적과 한계를 이해한다 단위 테스트에서 통합 테스트의 내용을, 통합 테스트에서 단위 테스트의 내용을 테스트하지 말라. 외부적인 상황은 배제하고 단위 모듈 자체에 대해 꼼꼼이 테스트한다 꼼꼼한 테스트, 중복되는 테스트가 아니라 통합 흐름에 대해 집중한다 중복된 테스트나 목적에 어긋난 테스트가 아닌 통합되는 모습에 따른 테스트를 수행한다
  10. 10. 6. 테스트 케이스를 통해 제품이 어떻게 동작하는지를 서술한다 특정 조건, 특정 상황에서 제품이 어떻게 동작하는지를 표현하는 테스트는 동료 개발자, 사용자에게 제품 스펙 이상의 설명서가 될 수 있다 사례) 아래의 테스트 코드는 실제 실행해 보지 않아도 제품이 어떻게 동작하는지 정보를 제공한다 입 력 값 기 대 값
  11. 11. 7. 누구나 이해 가능하도록 쉬운 테스트 코드를 유지하라. 기존에 작성되어 있던 테스트 코드의 불필요한 주석, 쓰이지 않는 코드, 적절하지 않은 메소드 명 등을 모두 정리하라 테스트 코드는 개발코드와 다르다. 과도하게 사용된 테스트 라이브러리 (자동 검증 기능, 자동 테스트 기능 등) 가 있다면 테스트 코드에 직접 표기하라 사례 1) 테스트 결과를 자동으로 검증해 주는 유틸 클래스 사용 -> 테스트 결과가 어떻게 동작해야 하는지 알기 어렵다. 사례 2) 테스트를 자동으로 수행하는 클래스 -> 어떤 테스트 데이터로 테스트를 수행하는지 알기 어렵다.
  12. 12. 8. 테스트 코드 자체만으로 어떤 내용을 테스트 하려는지 표현하라 의미있는 테스트 케이스명을 사용한다. 의미 전달을 위해서 의미있는 변수명을 선언하고 테스트에 사용한다 적절히 한 줄을 띄어 쓴다 사례) Max값보다 큰 min 값에 대한 테스트의 경우 . 케이스명 : biggerMinLongitudeNormal, . 변수명 : biggerThanMaxMinLongitude, biggerThanMaxMinLatitude
  13. 13. 9. 작은 변경에 대해서도 이 변경을 알려 줄 수 있는 테스트 코드를 작성하라 프로그램이 변경되면 테스트 케이스(코드)도 수정해야 하도록 테스트 케이스를 작성하라 프로그램을 변경했는데도 테스트 코드를 수정할 필요가 없다면 누락된 테스트가 있을 가능성이 높다 사례) 프로그램이 변경 되었는데도 테스트 코드에는 아무런 변화가 없었다 기존 코드를 분석한 결과 테스트 수행 후 결과값을 검증하는 부분이 빈약했었고, 이 부분을 강화하자 변경으로 인해 발생한 결함이 발견되었다
  14. 14. 10. 에러 발견시 발생 위치, 대략적 원인을 제공해 줄 수 있도록 테스트 코드를 작성하라 사례 1) 테스트 결과를 자동으로 검증해 주던 테스트 라이브러리를 제거하고, 각 테스트 코드별로 테스트 결과를 검증하도록 하여 어떤 검증에서 실패했는지 라인이 표시되도록 하고, 실패 메시지도 각 상황에 대해 별도로 표시되게 했다 사례 2) 테스트 코드 작성할 때 assert문에 실패 시 표시되는 메시지를 추가한다 [ assertXXX(“실패할때만 같이 표시되는 메시지”, ~기존 검증 구문~) ] 사례 3) 테스트 라이브러리에서 에러 발생시 해당 케이스 index, 입력값, 변수명, 기대값과 실제 값 등을 제공하도록 하였다. 사례 4) setUp, tearDown에서의 에러(TestSetupException)와 테스트 수행 과정 의 에러를 별개로 구분해서 테스트 실패 시 원인 파악이 잘 되도록 도왔다 사례 5) 테스트 ‘에러’와 ‘실패’를 구분해서 에러는 테스트 수행 중에 예상하지 못한 오류가 발생한 것, 실패는 테스트 수행 결과가 최초 작성한 것과 다른 경우로 상황을 분리했다
  15. 15. 11. 테스트 결과는 사람이 아닌 코드가 검증하도록 하라 사례 1) 테스트 수행 결과값을 system.out.println 을 표시하던 부분을 assert문으로 대체 System.out.println(“결과값 : ” + 결과값); assertEquals(“결과값이 기대값과 다릅니다.”, 기대값, 결과값); 사례 2) 상황에 알맞게 assert문을 작성한다 *assertEquals - 같은지 비교 *assertNull - null값을 리턴하는지 비교 *assertNotNull - 인자로 넘겨받은 객체가 null인지 판정하고 반대인 경우 실패로 처리한다. *assertSame - assertSame 은 expected 와 actual이 같은 객체를 참조하는지 판정하고 그렇지 않다면 실패로 처리한다. *assertNotSame - expected 와 actual이 서로 '다른' 객체를 참조하는지 판정하고, 만약 같은 객체를 참조한다면 실패로 처리한다. *assertTrue - boolean 조건이 참인지 판정한다. 만약 조건이 거짓이라면 실패로 처리한다. * fail - 테스트를 바로 실패 처리한다.
  16. 16. 12. assert문을 제대로 사용하라 - 의외로 assert문이 늘 성공하도록 작성된 테스트 코드가 많다 if( A != null) { assertNotNull(A); }else{ assertNull(A); } 사례 1) 테스트 결과를 System.out 하기만 하고 결과를 검증하지 않는 코드도 있다 사례 2) List 조회의 경우 실제 조회된 건이 없는데도 assert문이 누락된 경우가 있다. List resultList = 수행결과…; assertNotNull(resultList); // assertTrue(resultList.size() > 0); 실제로는 조회된 건이 없어서 테스트 실패
  17. 17. 13. 단순히 코드를 반복하지 않기 위하여 테스트 라이브러리를 만들지 마라 - 테스트 코드는 개발코드가 아니다. 코드가 반복되는 상태로 그대로 두는 방식(오픈 코딩)을 유지하라 별도 라이브러리를 사용하는 테스트는 검토하기도 어렵고, 디버그도 어렵고, 다시 수정하기도 어렵다 사례 1) 테스트 결과를 자동으로 검증해 주는 유틸 클래스 사용 -> 테스트가 실패하는 경우 원인을 직관적으로 알수 없고, 디버그하기도 어렵다. 사례 2) 테스트를 자동으로 수행하는 클래스 -> 어떤 테스트 데이터로 테스트를 수행하는지 알기 어렵다.
  18. 18. 14. 테스트 외부와 내부를 구분하라. - 테스트 실행과 사전조건/사후 행동을 구분하라 - 테스트 데이터 세팅부분과 테스트 실행을 구분하는 것도 좋은 접근이다 - 테스트를 이해하기 쉽고, 검토하기가 쉬워진다 - 별도의 테스트 사례 생성기를 적용할 수 있어진다 - 직관적으로 버그를 파악할 수 있다 setUp test tearDown setUpException tearDownException ** Junit 수행 결과 ** SuccessSuccessSuccessSuccess : 테스트 성공 ErrorErrorErrorError : 테스트 수행과정에서 예상하지 않은 Exception 발생 FailFailFailFail : 테스트 수행 결과가 기대한 결과(assert문 실패)와 다른 경우
  19. 19. 추가 - 대규모 프로젝트에서 Junit 수행 팁 가) 테스트 데이터, 공통 기능 공유 나) 테스트 전체에 대한 설정 일원화 (예: 테스트 수행 서버의 세팅) 다) DB 조회(쿼리 수행)를 위한 테스트 유틸리티 소개 라) ValueSetVO를 통한 반복적인 유효성 테스트 소개 마) 입력 값에 대한 일반적인 유효성 테스트 소개 바) Exception, Junit의 fail/Error를 통한 오류 직관성 강화 사) 모듈화를 통한 비즈니스 테스트
  20. 20. 가. 테스트 데이터, 공통 기능 공유 - 테스트 데이터를 별도 클래스에 분리하여 사용 CommonTestData 공통 기능 CommonTestData 공통 기능 AServiceTestData A의 유용한 실행코드 AServiceTestData A의 유용한 실행코드 BServiceTestData B의 유용한 실행코드 BServiceTestData B의 유용한 실행코드 CServiceTestData C의 유용한 실행코드 CServiceTestData C의 유용한 실행코드 AAAA BBBB CCCC
  21. 21. 나. 테스트 전체에 대한 설정 일원화 (예: 테스트 수행 서버의 세팅) XXTestCase AServiceTest BServiceTest CServiceTest 공통 설정용 변수 정의 대상 서버 수행 브라우저 수행, 성공 기준 테스트용 프레임워크 설정 파일명 그대로 사용
  22. 22. 다. DB 조회 모듈 등의 테스트 유틸리티 소개 테스트 코드 중간에 직접 쿼리를 입력해 DB 조회가 가능한 유틸리티를 제공하여 동적인 테스트 지원 현재는 이렇지만 나중에는? 테스트 작성 DBAccessManagerDBAccessManager ~~~~ ~~~~ DBDBDBDB
  23. 23. 라. 반복적인 유효성 테스트를 위한 라이브러리 작성 (사례) RESTful OpenAPI에 대해 입력 값의 타입별 반복적인 테스트 지원 null 빈문자빈문자빈문자빈문자 공백문자공백문자공백문자공백문자 정해진정해진정해진정해진 길이길이길이길이 이상의이상의이상의이상의 입력값입력값입력값입력값 특수문자특수문자특수문자특수문자, 한글한글한글한글/한자한자한자한자 개발된개발된개발된개발된 제품제품제품제품
  24. 24. 대상 변수 테스트 데이터 기대값 테스트 수행 junit.framework.AssertionFailedError: (Test Failed) Details : categoryName [ 2] Input value: , Expected code: CCT_1000, but Returned code : 200 [ 3] Input value: 123456789, Expected code: CCT_1002, but Returned code : 200 [ 5] Input value: 12345678901, Expected code: CCT_1002, but Returned code : 200 3 case(s) failed. 테스트 결과
  25. 25. 마. 일반적 유효성 테스트 케이스 소개 . 코드성 데이터 : 코드값 이외에 대한 테스트 . Date 타입 : 존재하지 않는 년, 월, 일에 대한 테스트, 시작/종료일 간의 선후 테스트 . 위도/경도, 각도(longitude, latitude, radius) : +-90도, +- 180도 초과/미만 값 등에 대한 테스트 . Description 테스트 : 전세계 서비스 특징에 따라 한글, 한자 등에 대한 테스트 . List 조회 테스트 : 정렬 필드, 필터링 문자식, pageNo, countPerPage 등에 대한 테스트 . 정수형, 더블형 등 : 음수, 0 , 주어진 타입의 최대값 등에 대한 테스트 . List, array 형태 : null, 주어진 데이터 없음 등에 대한 테스트
  26. 26. 여기까지. 중구난방, 두서없이 사례를 든 코드가 오래 전 코드 (JUnit3… 쿨럭) 그럼에도 불구하고 전하려던 메시지는………….. 테스트는 한 거 자체가 중요한게 아니라 어떻게 했느냐가 중요하다
  27. 27. “좋은 테스트케이스” 좋은 테스트 케이스는 다른 사람이 작성했더라도 수행하는 사람이 각 단계를 즐겁게 따라할 수 있는 케이스다. 테스트 케이스는 여러 사람에 의해 지속적으로 수행될 때 그 효용성이 극대화되기 때문이다. http://qualitypoint.blogspot.com/2009/05/writing-good-test-cases-and-finding.html
  28. 28. 감. 사. 합. 니. 다.

×