지난주 이런 저런 사고가 발생해서 정신없이 보내긴 했지만, 그래도 틈틈이 머리도 식힐 겸 JUnit 코드 분석을 시도했다.

3.8은 Cook’s Tour라는 JUnit 핵심설계의 과정을 담은 문서도 있고, Python이긴 하지만 TDDBE에 간단히 만드는 과정도 나와있고 해서 사실 분석하기가 어렵지 않았다. 3.8을 바로 보자면 조금 복잡한 느낌도 있지만, 초창기 버전인 1.0 소스부터 공개되어 있고, 2.0에서 살짝 확장되긴 했지만 거의 초기 설계와 코드를 그대로 유지해오고 있기 때문에 단계적으로 발전하는 과정을 보면서 분석하기에는 아무런 문제가 없었다.

오브젝트 프레임워크 구조인 1.0~3.x와는 달리 애노테이션을 사용하는 DSL스타일의 프레임워크로 바뀐 4.x의 코드는 처음 딱 열어볼 때부터 좀 복잡하다는 인상이 들었다. 단순한 setup-test-teardown구조가 아닌, 각종 애노테이션의 부가적인 기능의 조합(expected, timeout, ignore, beforeclass…, filtering, sorting)을 모두 처리해야 하고, 오브젝트 프레임워크가 아니니 8가지 패턴으로 깔끔하게 만들어진 3.x와는 다를 거라고 생각하기는 했지만, 좀 처럼 쉽게 눈에 들어오는 구조와 코드들이 아닌 것이 내심 불안했다.

켄트 벡이 소개한 JUnit 4.x에 적용했던 두가지 구현(혹은 설계) 패턴(nested method object, conditional factory)을 알고 있지만 그 것만으로는 프레임워크의 기본 구조를 이해하는 것도 쉽지 않았다. 코드를 따라 그림을 그려가면서 한참을 들여다 보고는 겨우 구조와 동작원리가 이해가 됐다. 3.x의 틀과는 완전히 딴판이다. 단지 애노테이션 방식으로 바뀌었기 때문은 아니다. 훨씬 더 근본적인 프레임워크의 확장과 유연성을 고려한 설계의 노력이 느껴지는 코드이다.

하지만 잠시 들여다본 코드는 그다지 인상적이지 않았다. 오히려 조금 실망스러웠다. 4.0이후로 메이저 업그레이드가 있었던 것도 아닌데.벌써 deprecated된 코드들이 제법 있다. 그러고 보니 켁트 벡이 JUnit의 공동개발자인 David Saff에게 "엉망인 코드를 정리하는데 함께 애써줘서 고맙다"는 얘기를 한 것이 기억난다. 그만큼 JUnit 4는 처음부터 실험적이고 모험적인 시도였던 것 같다. 한편으로는 오브젝트 프레임워크가 아니고, 그에 따라 테스트 클래스와 프레임워크의 결합이 거의 없는 수준이니 한편으로는 조금 자유롭게 다양한 실험을 해볼 수 있었던 것일지도 모르겠다.

4.7에서 도입되어서 열심히 실험중인 Inteceptor는 기존의 nested method object와 default runner builder 같은 개념을 좀 더 유연하게 확장하게 만들어준다. 예를 들면 @Test(expected=)를 이용해서 예외를 확인하는 기능을 이제는 인터셉터를 써서 대신할 수 있다. 아마도 테스트 메소드를 지정하는 것을 제외하면 거의 모든 기능을 인터셉터를 써서 새롭게 적용할 수 있을 것이다. 애노테이션이라는 이미 고정된 DSL 표현식을 넘어서서 다시금 오브젝트 프레임워크 시절의 무한한 확장가능성을 JUnit에 넣어줄 수 있는 것이 Inteceptor가 아닐까 싶다. 그래서 처음 이 Interceptor를 JUnit에 도입하던 날 켁트 벡이 흥분해서 트위터에 "JUnit geek들은 어서 최신 소스를 받아서 이 Interceptor를 써보라"고 했던 것 같다. 아마도 이 Interceptor가 중심이 되어서 JUnit이 새롭게 구성되는 시점이 5.0이 나오는 때가 아닐까 하는 예측을 해본다.

 

아무튼 JUnit 4.7는 아직 좀 지저분하다. 다양한 시도와 확장을 고려한 흔적들이 보인다. 어쩌면 필요없을 것 같은, 과도하게 유연하게 만든 코드들도 보인다. 언젠가 deprecated될지 모르겠다. 특히 internal 파트는 그렇다. 아직 4.x용 Cook’s tour가 나오지 않은 이유가 그런 것일지도 모르겠다. 어쨌든 좀 더 분석을 해보면 재밌는 모습을 찾을 수 있을 것 같다. 다양한 실험적인 시도들(theory, assume, maxcore, parallel, interceptor)도 살펴보는 것도 재밌을 것 같고.

 

한가지 떠오른 생각이 있다면. JUnit 4.x의 테스트 코드는 애노테이션을 제외하면 사실 프레임워크 구현에 매여있지 않다. 그렇다면 그 애노테이션을 그대로 사용하면서 새로운 테스트 프레임워크를 만들어보면 어떨까 하는 생각도 들었다. JUnit을 대치할 이유는 없으니, 뭔가 실험적이고 학습에 도움이 되는 시도를 해보는 것도 재밌을 것 같다는 생각이 들었다. JUnit의 nested object method 패턴을 스프링의 AOP나 callback/template를 이용해서 만들어보면 어떨까 하는 생각도 든다. 스프링으로 만드는 JUnit4 호환 테스팅 프레임워크라? 이거 구미가 땡기는데… 4.7 코드 분석이 모두 끝나면 한번 시도해 볼까?

자꾸 미루고 있던 JUnit 4.x의 설계와 코드 분석을 오늘부터 시작하기로 결심했다. 최근에 릴리스된 4.7 Snapshot 5/11 버전을 보고 더이상 미루면 안되겠다 싶었다. 오브젝트 프레임워크인 JUnit 1,2,3는 모두 분석해보았지만, DSL 프레임워크로 바뀐 4.x는 몇번 손을 대려다가 만만치 않은 분량의 새롭게 작성된 코드를 보고, 그걸 핑계 삼아 자꾸 미뤄왔는데 더 이상 미루면 안될 것이다.

내 시간관리 방침은 "중요한 일보다는 급한 일을 먼저하고, 급한 일보다는 재밌는 일을 먼저 하자" 인데(결국 중요한 일은 재밌는 일로 바뀌지 않으면 항상 뒷전이 되고 말 수 밖에 없다는…) 이 처럼 재밌는 것을 자꾸 미루면 되겠는가.

암튼 시작.

일단은 4.7에 추가된 Interceptor부터 살펴보고, 4.x의 바뀐 구조를 쭉 훝어볼 생각이다.

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha