유닛테스트의 효용성은?

fender의 이미지

아래 쓰레드에서 분기(?) 했습니다 :
http://bbs.kldp.org/viewtopic.php?p=141188#141188

lenani wrote:
UI 에서 유닛테스트를 할수는 없습니다.
처음부터 불가능 했습니다.
하지만 에러가 가장 많이 발생하는 부분은 UI가 아니라 UI 안쪽의 코드(gut)
입니다.
유닛테스트는 그 안쪽의 코드의 에러를 잡아내기 위한 도구입니다.

단위테스트도 계속 변동하는 개념이 아닐까 합니다. 예를들어 Mock-Object 테스팅을 말씀하셨지만 In-Container테스팅이나 Mock-Object 방식의 테스팅이 널리 쓰이기 전에는 컨테이너 위에서 돌아가는 컴포넌트들에 대한 단위테스팅 자체가 그다지 실용적으로 생각되지 않았습니다. 물론 백단에서도 에러가 나지만 실제 어플리케이션에서는 자잘한 GUI의 문제점들이 사용성을 해치는 가장 큰 원인이 아닐까 생각해 봅니다.

실제 이런 문제를 개려하기 위해 GUI나 웹을 대상으로 하는 단위테스팅 프레임워크들이 등장했지만 솔직히 효용성에 대해선 의문입니다.

lenani wrote:
저는 모든 객체의 속성을 public으로 열어둡니다.
사실 좀 웃기는게 private으로 막아놨다는 것은 코드 작성자 스스로가
'나는 이 속성을 밖에서 쓰지 않겠다'라고 말하는 것과 같습니다.
저는 그냥 밖에서 그 속성을 쓰지 않습니다.

음... 문제는 단위테스팅을 위해서는 해당 클래스가 어떤 상태에 있어야 할 경우가 많습니다. 이런 경우 대부분 public API로 나타나진 않지만 내부에 어떤 플래그가 설정이 되어야 한다던지 하는 제약이 있을 수 있습니다. 단위 테스트는 유틸클래스의 static 메소드를 테스팅하는데 이상적이지만 특히 네트워크나 컨테이너를 포함하는 프로그램들에는 그렇지 않다고 생각합니다.

물론 Mock을 써서 해결이 되는 경우도 있지만 오히려 많은 경우 제대로된 Mock Object를 만드는게 불가능하거나 엄청난 오버헤드를 유발하는 경우가 있습니다.

예를들어 FTP 클라이언트를 만든다면 하다못해 업로드, 다운로드, 로그인 등 기본적인 기능들에 대한 단위테스트만 한다고 해도 거의 서버를 하나 만들어야 될 수준이 아닌가요? 예를들어 FTP 클라이언트 API가 접속할 URL과 계정정보를 받아서 다른 쓰레드에서 로그인 처리를 한다고 할 때, 또 만약에 이런 상황에서 다운로드 기능에 대한 단위테스트를 만들려면 어떻게 해야 할까요?

분명 public API에는 드러나지 않지만 FTP 커넥션이 있고 로그인이 된 상황에서만 다운로드가 동작하는 건 자명합니다. 그렇다면 선택의 여지는 테스트 하려는 FTP 클라이언트 모듈에 실제 로그인 정보를 주거나 아니면 스스로 접속이 되어 있다고 '믿게' 만들어야 합니다. 전자의 경우 FTP 서버 역할을 하는 Mock 프레임워크가 필요하고 후자는 단위테스팅이 아니면 불필요한 API를 추가해야 합니다.

전자의 경우 Mock 프레임워크를 만든다면 다운로드라는 단순 기능을 테스트하기 위해 일단 21번 포트를 통해 FTP와 동일한 방식으로 로그인 및 업/다운로드를 할 수 있는 가상의 FTP 서버를 만들어야 합니다. 또한 극단적인 가정이지만 만일 "1기가가 넘는 파일을 업로드할 때 문제가 없는가?"와 같은 기능을 테스트 한다면 테스트 케이스에서 로컬에 1기가 파일을 만들어서 업로드하는 기능도 필요할 것입니다.

이 정도 복잡한 Mock 프레임워크를 만드는 것은 사실상 테스트 대상인 FTP 클라이언트 만큼이나 어렵습니다. 또한 그만큼 복잡성이 증가한다는 건 단위테스트 코드 자체가 다시 단위 테스트를 요구할 정도로 버그 발생으로 인해 결함있는 테스트가 될 확률도 있다는 뜻입니다.

극단적인 예를 들었지만 주목할 점은 과연 이런 삽질을 하는 목적이 무엇인가에 대한 의문을 가져야 한다는 점입니다. 단지 'XP를 따르기 위해' 테스팅을 하는게 아니라면 위와 같은 경우는 단위테스팅이 무의미하지 않을까 싶습니다.

개발한 FTP 클라이언트가 제대로 로그인/다운로드 기능을 처리하는 지 보려면 그냥 한 번 해보는게 빠르니까요 :)

lenani의 이미지

꼭 FTP 클라이언트를 만들기 위해서 FTP 서버를 만들어야 하는 것은 아닙니다.
만약 FTP를 사용하기 위해서 socket을 사용한다고 했을때
socket 함수들의 interface를 모방하는 Mock을 만들면 됩니다.
그리고 그 함수들을 이용하기 위한 인자와 출력값을 우리가 원하는 값으로
입력받고 출력하게 만들기만 하면 됩니다.

Mock을 만드는것은 제 생각에는 UI를 제외한 모든것을 만들수 있습니다.
오버헤드는 당연히 발생합니다.
하지만 저는 반대로 오버헤드를 줄이기 위해서 테스트를 합니다.
잘못된 코드로 인해서 발생하는 오버헤드를 말하는 겁니다.
만약 코딩을 하는데 쓰는 시간과 디버깅을 하기 위해서 쓰는 시간을 모두
합친다면 어느 정도까지 나올까요?
제가 믿는 것은 테스트와 코딩을 하는 것이 코딩과 디버깅에 쓰는 비용보다
적게 나온다는 것 입니다.

그리고 한가지 중요한 것은 코드 수정후 언제든지 자동화된 검사(?)를 할수
있다는 것입니다.
그 결과 코드 수정이 기존 코드의 로직을 해치지 않는다는 것을 보장 받을수
있습니다.
만약 6개월 후에 기존 프로그램에 어떤 기능을 덧붙여야 한다면 그 기능을
붙인후 어떻게 올바로 동작한다고 확인할수 있겠습니까?
code inspection 없이는 불가능 합니다.

당연히 Mock이 필요 없을 경우도 있습니다.
간단하고 확실히 로직이 올바르게 작동한다는 생각이 든다면 저는 Mock
을 사용하지 않습니다.
하지만 저의 경험에 의하면 그런 곳에 꼭 버그가 있더군요.

lenani의 이미지

죄송합니다.
바로 답변을 달아야 했는데 제가 어딜좀 다녀오느라고요. :oops:

lenani의 이미지

음...
Thread를 분기하기는 했지만 역시 원래의 Thread에서
유닛 테스트에 관한 사항이 논의되고 있습니다.
앞으로 원래 Thread에서 유닛테스트에 관한 사항이 나오면
이곳에 글을 올리겠습니다.

redbaron의 이미지

같이 일하시는 분이 정말 Unit Test를 잘 활용(?)하시는 모습을 보고 감탄해서 글을 올립니다.

일단 XP니 Unit니 하는 개념은 조금 제외 하고라도 Testing의 필요성 자체는 대단히 중요하다는건 모두 인식하고 있는 사실입니다.

같이 일하시는분의 경우에 기능별로 쪼개놓고 그 기능별로 Test해서 하나씩 붙여가는 작업을 하시더군요.(저는 이런것도 Unit으로 쪼개고 Test하니 Unit Test라고 생각했지만..제가 잘못 알고 있는건지도..)

일단 Test가 완료된 기능(Class가 되었던 Method가 되었건)에 대해서는 안심하고 전체코드에 붙일수 있으니까요. 그것만으로도 개발속도가 꽤 빨랐던걸로 생각합니다.

여러가지 이견이 많겠지만 저런 이유(혹은 경험)만으로도 Unit Test의 효용성이 충분한 것은 아닐까요?

lenani의 이미지

redbaron wrote:
같이 일하시는 분이 정말 Unit Test를 잘 활용(?)하시는 모습을 보고 감탄해서 글을 올립니다.

일단 XP니 Unit니 하는 개념은 조금 제외 하고라도 Testing의 필요성 자체는 대단히 중요하다는건 모두 인식하고 있는 사실입니다.

같이 일하시는분의 경우에 기능별로 쪼개놓고 그 기능별로 Test해서 하나씩 붙여가는 작업을 하시더군요.(저는 이런것도 Unit으로 쪼개고 Test하니 Unit Test라고 생각했지만..제가 잘못 알고 있는건지도..)

일단 Test가 완료된 기능(Class가 되었던 Method가 되었건)에 대해서는 안심하고 전체코드에 붙일수 있으니까요. 그것만으로도 개발속도가 꽤 빨랐던걸로 생각합니다.

여러가지 이견이 많겠지만 저런 이유(혹은 경험)만으로도 Unit Test의 효용성이 충분한 것은 아닐까요?

저도 이점 매우 공감합니다.

tasy의 이미지

redbaron wrote:
일단 Test가 완료된 기능(Class가 되었던 Method가 되었건)에 대해서는 안심하고 전체코드에 붙일수 있으니까요. 그것만으로도 개발속도가 꽤 빨랐던걸로 생각합니다.

여러가지 이견이 많겠지만 저런 이유(혹은 경험)만으로도 Unit Test의 효용성이 충분한 것은 아닐까요?

저도 그렇게 생각합니다.

일단 XP나 TDD나 Unit Testing 이나 Rule이라기 보다는 하나의 Tool로써 생각하는게 좋지 않을까 생각되는데요.

도구는 용도에 맞게 나름데로 사용하는게 최고의 효율을 발휘할 수 있듯이 Unit Testing도 나름데로 바른 용도에 사용하는게 최고일 것 같습니다.

사용하는데 무리가 발생하다 싶을 정도면 사용하지 않는게 좋겠죠.

---------
Byeongweon Moon
http://tasy.jaram.org/blog
사랑하면 알게 되고 알면 보이나니 그때에 보이는 것은 전과 같지 않으리라.

fender의 이미지

음... 조금 정의를 명확히 하는게 좋을 것 같습니다. redbaron님께서는 단순한 의미로 프로그램을 기능별로 '모듈'이나 '단위'로 나눠서 전체 시스템에 붙이기 전에 개발자가 직접 동작 여부를 확인 하는 것을 말씀하시는 것 같습니다.

이런 식의 테스트는 개발자라면 당연히 신경을 써야 하는 부분이 아닐까 생각합니다. 최소한 자기가 만든 걸 확인도 안하고 내보낸다면 개발자 자격이 없으니까요 :)

원래 이야기가 되던 XP의 '단위테스트'와 이런 넓은 의미의 '테스트'의 가장 큰 차이점은 전자는 자동화되어 반복할 수 있다는 점입니다. 즉, 주로 프로젝트를 빌드할 때마다 자동으로 테스트 케이스들을 실행해서 어떤 regression이 발생했는지를 검사하는게 주요 목적이며 제가 이야기한 효용성의 문제는 이런 형식화된 테스트에 대해 국한해서 생각해 주셨으면 합니다.

예를들어 서버에서 돌아가는 모듈이 있다면 단순한 의미의 테스트를 수행하기 위해선 그냥 개발자가 한번 돌려보고 다양한 방법으로 결과를 확인하면 됩니다. 반면 단위테스트를 작성하려면 해당 모듈은 서버에서만 동작하기 때문에 In-Container 방식으로 특화된 테스팅 프레임워크 위에서 돌리거나 서버 기능을 흉내내는 Mock Object 방식으로 별도 코딩을 해야 합니다.

제가 토론 해보고 싶은 주제는 이런 경우 테스트를 작성하는 오버헤드보다 과연 이로 인해 얻는 효용성이 크다고 할 수 있을까 하는 부분입니다. 또 모듈의 내부 구현을 알아야 제대로 테스트가 가능한 경우 등 단위테스트에 따르는 문제점들도 같이 이야기해보면 좋을 것 같습니다.

----------------------------
[서명] 그놈 한국 사용자 모임 - 그놈에 대한 모든 것! - 게시판, IRC, 위키, 갤러리 등등...

juneaftn의 이미지

간단하게 제 생각을 정리해 보겠습니다. 자세한 내용은 http://xper.org 에 제가 쓴 글들을 참고하세요.

1. 막 오브젝트가 똑똑한 것은 나쁜 냄새(bad smell)입니다.
2. 테스트에는 레벨이 있습니다. 단위, 통합, 시스템, 승인 테스트 등등
3. 설계가 좋으면 막 오브젝트가 별로 필요없습니다.
4. 테스트는 ROI를 생각해서 합니다.
5. 테스트 인프라스트럭춰는 가능하면 가볍게 가져가는 것이 좋습니다.
6. XP에는 "법칙은 법칙일 뿐이다"는 법칙이 있습니다.

최근 자바 개발자 컨퍼런스에서 발표했던 자료를 보시면 하루 수천만 페이지뷰의 웹사이트를 테스트 자동화를 지켜가면서 개발한 사람들의 이야기를 들을 수 있습니다. 1300여개의 테스트가 2분여만에 통과하는데 이 테스트는 DB 테스트를 포함 거의 시스템의 전체를 꿰뚫습니다.

http://xper.org/wiki/xp/_b1_e2_b9_ce_c7_d1_b9_ae_c8_ad_c0_cc_be_df_b1_e2

lenani의 이미지

juneaftn wrote:
간단하게 제 생각을 정리해 보겠습니다. 자세한 내용은 http://xper.org 에 제가 쓴 글들을 참고하세요.

1. 막 오브젝트가 똑똑한 것은 나쁜 냄새(bad smell)입니다.
2. 테스트에는 레벨이 있습니다. 단위, 통합, 시스템, 승인 테스트 등등
3. 설계가 좋으면 막 오브젝트가 별로 필요없습니다.
4. 테스트는 ROI를 생각해서 합니다.
5. 테스트 인프라스트럭춰는 가능하면 가볍게 가져가는 것이 좋습니다.
6. XP에는 "법칙은 법칙일 뿐이다"는 법칙이 있습니다.

최근 자바 개발자 컨퍼런스에서 발표했던 자료를 보시면 하루 수천만 페이지뷰의 웹사이트를 테스트 자동화를 지켜가면서 개발한 사람들의 이야기를 들을 수 있습니다. 1300여개의 테스트가 2분여만에 통과하는데 이 테스트는 DB 테스트를 포함 거의 시스템의 전체를 꿰뚫습니다.

http://xper.org/wiki/xp/_b1_e2_b9_ce_c7_d1_b9_ae_c8_ad_c0_cc_be_df_b1_e2

음... 흥미가 생기는군요.
좀더 자세히 설명해 주시면 감사하겠습니다.