본문 바로가기

IT 정보

개발자 동료에게 큰 혼란을 주는 테스트 작성 방법! (테스트 코드 함정)

 

단위 테스트는 영원히 계속되어야 합니다. 일단 작성되고 나면 단위 테스트는 코드베이스에 머물면서 기능 동작 검증과 회귀 검증의 역할을 수행합니다. 테스트가 코드베이스에 통합된 후에는 해당 테스트로 혼란을 일으킬 기회가 사라진 것처럼 보일 수 있습니다.

 

실제로는 그렇지 않습니다..!

 

똑딱거리는 시한폭탄과 같은 단위 테스트를 작성한다고 상상해 보세요. 처음에는 통과해 코드베이스에 들어가지만, 이는 가까이 있는 불행한 동료를 잡을 준비가 되어 있는 함정과도 같습니다.

 

알 수 없는 미래에 알 수 없는 이유로 테스트가 쉽게 깨지게 만들어, 복잡한 테스트 코드를 들여다 보던 동료들이 당신의 이름과 육두문자를 외치게 할 만한 테스트를 작성할 수도 있습니다.

 

 

 

  • 특정 컴퓨터에서만 돌아가는 테스트를 짜라

"음, 내 컴퓨터에서는 되는데?"

 

지옥에는 이 문장을 사용하는 사람들을 위한 특별한 장소가 있습니다. 여기에 자리를 예약하는 방법은 다음과 같습니다.

 

한 시스템에서는 프로그램이 올바르게 동작하지만 다른 시스템에서는 실패하는 경우가 흔합니다. 물론 다른 프로그래머들은 이런 결과를 피하고자 최선을 다 합니다. 하지만 당신은 적극적으로 이를 추구합니다.

 

이런 불일치가 발생하는 일반적인 이유 중 하나는 프로그램이 시스템마다 특성이 다른 일종의 외부 리소스를 참조하기 때문입니다. 이 사실을 이용해서, 초기에는 작동하지만 나중에 다른 사람이 실행할 때 고장나도록 하는 테스트를 작성할 수 있습니다. 

 

예를 들어, 시스템에 있는 리소스에 대한 테스트를 수행하는 경우, 당신 컴퓨터에서는 작동하지만 동료들이 자신의 컴퓨터에서 실행할 때는 실패합니다. 다음 스크립트는 간단한 음식 메뉴 프로그램을 테스트합니다. 프로그램은 텍스트 파일에서 메뉴의 이름을 읽습니다. 

 

 

 

모두 잘 되지만, 당신의 테스트 스크립트는 loadMenu 메소드를 다음과 같이 겁증합니다.

 

 

하드코딩된 파일 경로는 자신의 컴퓨터에 있는 개인 홈 폴더를 가리킵니다. 다른 곳에는 존재하지 않는 위치로 말이죠. 즉, 테스트는 통과하지만 다른 시스템에서는 실패합니다. 

 

물론 하드코딩된 파일 경로가 너무 빨리 오류를 발생시켜 동료들이 쉽게 발견할 수 있지만, 다른 미묘한 기술도 있습니다. 예를 들어, 이전 테스트를 환경변수를 사용하도록 변경하면 컴퓨터에 종속적이지 않은 테스트를 작성한 것처럼 보일 수 있습니다. 

 

 

CD의 값은 Microsoft Windows 시스템에서 사용할 수 있으며, 프로그램이 실행 중인 현재 디렉터리의 위치를 기억합니다. 즉, 테스트는 Windows가 서리된 모든 컴퓨터에서만 동작합니다. Linux나 OS X와 같은 다른 플랫폼은 CD 환경 변수를 지원하지 않습니다(이 경우 일반적으로 PWD-Present Working Directiory라 합니다). 따라서 Linux를 좋아하거나 Apple을 좋아하는 동료가 나타나 테스트를 실행하려고 시도하면 실패하고 말 것입니다. 

 

 

※ 주의하기!

 

동료들을 정말로 짜증나게 하고 싶지 않다면, 테스트하고 있는 프로그램의 모든 측면을 모든 컴퓨터에서 재현할 수 있어야 합니다. 여기에는 프로그램과 프로그램이 의존하는 외부의 모든 것을 포함합니다. 외부 리소스는 환경에 따라 다르기 때문에 세심한 관리가 필요합니다.


이전 예제에서는 파일 경로를 보여 주었습니다. 프로그램에서 파일을 사용할 때, 파일 시스템의 가변성을 제어해야 합니다. 항상 다음과 같이 가정할 수 없다는 점을 기억하세요.


■ 파일 시스템 내의 프로그램 위치(사용자는 어디에나 설치할 수 있음)
프로그램이 설치된 플랫폼(예: Windows나 Linux) 및 이에 따라 처리 중인 파일 시스템


이러한 이유로 플랫폼에 독립적인 수단을 사용하는 파일을 참조하고, 상대 경로의 사용을 고려해야 합니다. 환경변수를 사용하여 테스트해야 한다면 테스트 실행 스크립트는 실행 전에 해당 변수 설정을 포함해야 합니다.


또 다른 일반적인 문제는 타사 라이브러리와 같은 외부 의존성입니다. 컴퓨터에 필요한 라이브러리가 있다고 해서 반드시 다른 모든 사람이 가지고 있는 것은 아니죠. 테스트를 실행하기 위해 외부 의존성이 필요한 경우, 그 의존성을 얻는 것은 빠르고 고통 없는(또한 가급적이면 자동) 프로세스여야 합니다. 외부 종속성을 식별하려면 이름, 버전과 같은 몇 가지 정보가 필요합니다. 이름만 참조하고 FooLibrary 버전 3 전용 기능을 사용하면 버전 2만 설치된 동료에게 문제가 생깁니다.

 

 


 

  • 넓은 곳을 확인하게 하라

테스트 제품군에서 오류가 발생하면, 동료 중 한 명이 원인을 디버깅하는 일을 맡게 됩니다. 동료들은 틀림없이 디커깅은 좋은 것이라고 말합니다. 그들이 그렇게나 사랑하는데, 그들을 위해 더 많은 디버깅 작업을 만들어 볼까요?

 

해당 유닛의 동작 범위를 넘어서 단위 테스트의 범위를 확장함으로써 더 많은 작업을 만들어 낼 수 있습니다. 테스트에 몇 개의 프로그램 유닛을 추가하면, 추가 유닛의 문제로 인해 프로그램 유닛이 손상될 수 있습니다. 즉, 오류를 디버깅하는 사람은 문제를 찾기 위해 더 많은 곳을 검색해야 한다는 뜻입니다.

 

예를 들어, 고객으로부터 온라인 주문을 발송하려면 일반적으로 여러 단계가 필요합니다. 이 코드 샘플은 프로그램으로부터 발송 프로세스를 보여 줍니다. 

 

 

 

Order.dispatch의 테스트 실패가 관측되었다는 것은 Order 클래스에 에러가 발생했다는 것입니다. 그러나 dispatch 메소드는 다른 클래스의 메소드에 따라 다릅니다. Order.dispatch 메소드에 대한 테스트는 OrderChecker.validate 및 BankConnection.fundsReceived 메소드의 동작도 포함합니다. 이 테스트 메소드는 OrderChecker나 BankConnection의 버그로 인해 실패할 수 있으므로 동료에게 디버그할 코드를 더 많이 줄 수 있습니다.

 

 

 

※ 주의하기!

 

테스트를 작성할 때는 어느 정도의 레벨에 테스트의 초점을 맞추어야 하는지 명확히 해야 합니다. 이전 예제처럼 여러 개의 협업 유닛을 함께 테스트해 보는 것은 더할 나위 없이 타당하고 유용하죠. 이는 통합 테스트의 예입니다. 이런 테스트는 올바른 유닛이 서로 “연결되어” 있을 때 오류가 발생할 가능성이 크므로, 프로그램의 다양한 모듈이 예상대로 동작하는지 확인합니다.


그러나, 단위 테스트는 테스트 범위를 넓히기 전에 단 하나의 유닛에 초점을 맞추어 올바르게 작동하는지 확인합니다. 그렇게 하면 한 유닛에서 버그가 나타날 때, 버그가 있는 곳을 찾기 위해 다양한 협업 모듈을 선택할 필요가 없습니다. OrderTest 클래스가 실패하면 Order 클래스에만 버그가 발생한 것입니다.

 

 

《동료들 뒷목 잡게 만드는 나쁜 프로그래밍 습관》

 

예스24 교보문고 알라딘 인터파크 

반응형