테스트라는 것은 참 오묘하다. 코딩이 끝나고 기능이 잘 돌아가는지 검증하기 위해서 작성하는 테스트가 있는 반면, 코드를 만들지도 않은 상태에서 그 코드가 어떻게 동작해야 할지를 먼저 테스트로 만드는 테스트우선(Test First) 또는 테스트주도(Test Driven) 방식의 테스트도 있다. 또 하나 내가 즐겨 작성하는 테스트가 있는데 그것은 내가 만들지 않은 오픈소스 또는 상용 제품이나 프레임워크에 대한 테스트를 작성하는 것이다.

그런 소프트웨어들은 알아서 잘 만들어서 공개하거나 판매했을 텐데 구지 내가 다시 테스트를 만드는가 의아하게 생각될 수 있을 것이다. 이유는 간단하다. 그 제품의 기능을 공부하기 위해서이다.

새로운 프레임워크의 기능에 대한 안내를 매뉴얼에서 확인하고, API 문서를 읽으면 바로 안심하고 가져다 쓸 수 있을까? 아주 간단한 API의 경우를 제외하면 나는 그럴 자신이 없다. 그래서 먼저 그 API나 기능을 사용하는 테스트를 작성한다. 만약 내가 이해한대로 그 기능을 검증하는 테스트를 만들었는데 원하는 결과가 나오지 않으면 일단 내가 잘못 이해한 것일 가능성이 높다. 따라서 좀 더 학습이 필요하다. 필요한 정보를 찾아보고 코드를 수정하면서 테스트가 성공하도록 만든다. 그러면 적어도 그 기능을 사용할 때 코드는 이런식으로 사용하면 안전하다는 확신이 들고, 그 사용방법을 코드로 만들어 두었기 때문에 실전에서 적용하는데 유리하다.

물론 간단히 main()에다가 기능을 만들어서 콘솔에 찍히는 값 정도를 체크하는 방법으로 확인할 수도 있다. 그것도 일종의 테스트니깐. 하지만 JUnit 같은 자동화된 테스트가 훨씬 나음은 두말할 것도 없다.

그래서 내가 개발하는 프로젝트의 테스트 코드 안에는 사용하는 프레임워크나 API의 기능에 대한 테스트 코드를 만드는 패키지가 따로 있다. 이렇게 만든 3-rd party 제품에 대한 테스트 코드는 나중에 버전이 업그레이드 되었을 때 다시 한번 유용하게 사용할 수 있다. 만약 새로운 버전에 버그가 있거나 호환성에 문제가 있으면, 기존 버전으로 만든 테스트를 통과하지 못할 수 있다. 그렇다면 메인 애플리케이션에도 역시 오동작 할 가능성이 높다는 것을 알 수 있다.

이렇게 남이 만든 제품에 대해서 테스트를 작성하는 것은 그 API의 사용법에 대한 학습과 호환성 확인차원에서 큰 효과가 있다. 또한 테스트 코드를 만드는 방법을 연구해두면 후에 그 기능을 사용하는 자신이 만드는 코드에 대한 테스트를 작성할 때도 도움이 된다. 테스트 작성에 대한 연습 내지는 좋은 틀을 만들어 줄 수도 있기 때문이다. 또한 팀으로 개발하는 경우, 다른 팀원들에게 해당 API를 사용하는 일관성 있는 코딩 정책을 보여주는데도 도움이 된다.

 

사실 이런 테스트 작성방법에 대해서 별다른 이름을 생각해본 적은 없는데, 최근에 Kent Beck의 테스트주도개발(Test-Driven Development By Example – 나는 Kent Beck에게 직접 싸인 받은 책으로 읽는다 ^^V)을 다시 읽으면서 이런 방식을 학습테스트(Learning Test)라고 부른다는 것을 알게되었다. 학습테스트는 이렇게 3자에 의해서 개발된 기능을 가져다 사용할 때 그 것을 이해하는지를 검증하고 사용방법을 학습하기 위해서 작성하는 테스트패턴의 한가지로 소개된다.

 

학습테스트는 프로젝트에서 당장 사용할 기능에만 적용할 수 있는 것이 아니다. 말 그대로 다른 소프트웨어에 대한 기능과 사용방법을 이해하기 위해서 만드는 것이기 때문에 순수하게 새로운 기술이나 제품을 학습하는데도 적용할 수 있다.

나는 내가 중요하게 생각하는 프레임워크를 학습할 때 그에 대한 테스트 프로젝트를 만들어서 이용한다. 예를 들어서 스프링의 레퍼런스 문서를 공부한다고 하면, SpringReference라는 프로젝트를 만들고 그 안에 각 챕터에 소개된 기능을 테스트 코드로 만들어서 직접 확인해본다. 이런 학습방법은 매우 효과가 좋다. 많은 경우 책이나 문서를 가지고 학습할 때 간단한 예제를 만들어 본다. (최소한 그것도 안해보고 공부했다고 하는 사람을 나는 이해할 수 없다.) 문제는 그렇게 예제나 참조구현(reference implementation)을 만들다 보면 제품의 한가지 방법이나 스타일, 그것도 가장 단순하고 쉬운 것만 해보게 되기 쉽다. 요즘 인기가 있는 다양한 프레임워크들은 한가지 기능을 구현하는 방법을 다양하게 제공하고 그것을 사용하는 개발자에게 적절한 선택을 요구하는 경우가 많다. 범용적인 프레임워크일 수록 그런 경향이 높다. 스프링은 그 중에서도 악명(!)이 높다. Spring is about choice라는 말이 괜히 나온게 아니다. 문제는 다양한 선택의 방법을 골고루 시도해보지 않고는 그 각각의 장단점과 특징을 이해하기 힘든 경우가 많다. 당장 필요해서 써먹을 것이 아니면 문서만 대충 훑고 넘어가는 식이라면 나중에는 그런 것이 있었는지 기억조차 못할 가능성이 높다.

그래서 꼼꼼하게 학습하기를 원한다면 레퍼런스 매뉴얼이나 API문서에 나와있는 여러가지 케이스에 대해서 최소한 하나씩의 테스트 코드를 만들어 볼 필요가 있다. 자기 손으로 코드를 만드는 것과 그냥 남이 만든 코드 샘플을 보기만 하는 것은 학습결과에 큰 차이를 가져온다.

 

물론 기능을 모두 테스트로 작성해보는 것은 또 다른 도전을 가져다 준다. 바로 다양한 기능을 테스트로 작성하는 실력도 필요하다는 것이다. 하지만 자동화된 테스트 코드로 검증된 적이 없는 제품은 쓰레기 취급 당하는 요즘 같은 시절에 테스트 작성 실력을 키우는 것까지 함께 배울 수 있으니 얼마나 도움이 되겠는가.

나는 스프링의 기능에 대한 테스트를 작성하면서 스프링을 이용한 애플리케이션의 테스트 방법에 대해서도 많은 것을 새롭게 배우게 되었다. 테스트를 작성할 대상이 만약 오픈소스이고 그 자체의 테스트코드가 함께 제공된다면, 내가 테스트 해보고 싶은 기능에 대해서 그 개발자들은 어떻게 테스트를 만들었는가를 살펴볼 수 있을 것이다. 그 안에서 배울 수 있는 것도 무긍무진하다.

 

나는 SpringAOP의 기능을 테스트 코드로 만들어보면서 AOP모듈을 테스트하는 방법에 대해서 고민한 적이 있다. 일반적인 OOP로 작성된 코드는 실행과정이 그대로 드러나있고 파라메터와 리턴 값을 통해서 결과를 확인해볼 수 있기 때문에 테스트를 작성하는데 별다른 어려움이 없다. 구지 필요하다면 테스트 오브젝트의 협력객체에 대한 스텁이나 목오브젝트를 이용하는 정도랄까. 그런데 AOP의 모듈은 포인트컷을 통해서 벌크로 찾아낸 조인포인트에 대해서 코드에서는 드러나지 않는 기능을 위빙(weaving)을 해버리기 때문에 메소드의 call 경로를 따라서 검증하는 것이 어려울 수가 있다. 어드바이스에서 리턴값이 조작되는 특별한 경우라면 모를까.

그래서 주로 사용한 방법이 static이나 싱글톤 같은 글로벌한 영역에 플래그를 두고 애스팩트의 실행여부나 값등을 체크하는 방법을 주로 써왔다. 그런데 그런 방식은 좀 불편하다. 만약 여러 테스트가 멀티쓰레드 환경에서 동시에 돌아가게 된다면 테스트 결과가 보장도 안된다. 그래서 스프링의 AOP관련 테스트를 살펴보았다. Adrian Colyer가 작성한 AOP관련 테스트에서 주로 사용한 방법은 애스팩트의 실행이 필요로 하는 어드바이스에서 Exception을 던지는 것이었다. 그리고 테스트에서는 그 Exception을 검증하는 방법을 사용하면 AOP에 의해서 어떤 경로에서 실행이 되도 쉽게 그 테스트가 가능하다는 것을 알게되었다. 이후에 작성한 AOP 테스트에서는 그 방법을 많이 사용하게 되었다. 덤으로 AssertThrows라는 Exception발생을 검증하는 템플릿 스타일의 클래스도 알게 되었다.

 

테스트를 작성하면서 하는 공부는 그냥 문서만 스르륵 읽어가는 것에 비해서 시간은 좀 더 걸릴지 모른다. 하지만 지루하게 책이나 문서만 읽는 것에 비해서 훨씬 재밌고 효과도 뛰어나다. 지루해지기 시작하면 모든 공부는 거기서 끝장이다. 물론 모든 내용을 다 테스트로 만들 필요는 없을 것이다. 흥미로운 것을 먼저 시도해보고, 나중에 어려운 내용에 도전해보는 것도 좋겠다. 탄력이 좀 붙으면 간단한 예제를 가지고 웹 테스트 레벨까지 도전해보는 것도 좋을 것이다. 요즘 스터디모임을 많이 하는데 학습테스트 작성을 이용해서 스터디모임을 해보는 것도 좋을 것 같다. 한 챕터에 대해서 주요한 기능을 선정한 후 각자 테스트를 작성해오고 모여서 그 코드를 서로 비교해 가면서 느낌을 나누고 토론해 보면 어떨까.

Related posts:

  1. AppFuse DAO Test 코드의 문제점
  2. Spring 3.0 (19) Test 모듈의 선택라이브러리 분석
  3. Spring기반의 Hibernate DAO Unit Test 만들기

Facebook comments:

to “학습테스트(Learning Test)를 이용해서 공부하기”

  1. This is a topic that is near to my heart… Take care! Exactly where are your contact details though?

Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha