사상

테스팅 프레임워크는 직접 만들어 써보자

PaxCaelo 2023. 10. 10. 11:08

기존 블로그에 있던 글 중에서 남기고 싶은 것들을 옮겨봐야겠다. 

2008년에 쓴 글이다. TDDBE/테스트주도개발 책을 읽으며 가장 감탄하게 만들었던 xUnit 만들기에 관한 이야기이다. 

한참 뒤에 라이브코딩으로 xUnit 만드는 걸 유튜브에 공개했다. 


xUnit의 시초이자 자동화된 테스팅 프레임워크 붐의 기원은 잘 알려진 대로 JUnit이다. 물론 그 이전에도 여러 개발자들이 스스로 테스트 코드를 작성하기 위해서 여러 가지 툴을 직접 만들어서 사용했다고 한다. 하지만 JUnit처럼 공개된 단순한 프레임워크이면서 빠르게 많은 개발자들에게 영향을 주고, 실질적인 테스트의 가치를 느끼게 하고 테스트 작성을 실천하게 도와준 것은 없었다.

JUnit의 첫 버전은 Erich Gamma와 Kent Beck이 함께 97년 OOPSLA에 참여하기 위해서 쮜리히에서 애틀란타로 가는 비행기 안에서 작성되었다고 한다. 그 짧은 시간 동안 (그것도 노트북 배터리의 제한을 받아가면서) JUnit을 개발했다는 것이 잘 믿어지지 않을지 모르지만 사실이다.

JUnit was born on a flight from Zurich to the 1997 OOPSLA in Atlanta. Kent was flying with Erich Gamma, and what else were two geeks to do on a long flight but program? The first version of JUnit was built there, pair programmed, and done test first (a pleasing form of meta-circular geekery).

- XUnit

JUnit의 기원은 Kent Beck이 94년 즈음부터 만들어 써오던 SUnit이다. SUnit은 사실 어떤 특정 프레임워크를 지칭하는 것은 아니다. 스타일과 구조는 비슷할지 몰라도 Kent Beck은 매 프로젝트마다 그에 적합하게 테스팅 프레임워크를 만들어서 사용했고, 다른 개발자들도 그렇게 하기를 원했다.

There was no single kent-beck-smalltalk-unit-testing framework. Kent wants people to control their own environment, so he liked to have each team build the framework themselves (it only took a couple of hours), that way they would feel happy to change it to suit their particular circumstances – essentially it was really a Seedwork.

- XUnit

 

JUnit 문서에도 나와 있듯이 심플한 테스팅 프레임워크는 몇시간이면 개발이 가능하다. 물론 그 자체를 TDD로 개발하면서 말이다. 테스트주도개발(Test Driven Development by Example)에도 파이썬을 이용해서 xUnit을 TDD로 만드는 예제가 나와있다. 파이썬을 잘 아는 개발자라면 그것을 따라 하는데 한두 시간이면 충분할 것이다.

 

Kent Beck의 테스팅 프레임워크는 매우 간결하다. 그가 만들어 사용하던 테스팅 프레임워크는 초기부터 3개의 핵심 클래스로 구성되어있었다. 바로 TestCase, TestSuite, TestResult이다.

I wrote SUnit in 1994 I think.

I wrote this up as a little three class (TestCase, TestSuite, TestResult) framework with, I think, twelve methods. The clients were able to understand and use it (they still are to this day).

The framework was so simple that I couldn’t imagine that it had value, even though I thought it was aesthetically cool, so I gave it to the smartest programmer I knew and asked him to try it. When I didn’t hear back for a month I figured, “Okay, cool little idea but not big deal.”

- A Brief History of Test Frameworks에 나온 Kent Beck의 답변에서

 

이 간결함은 JUnit에도 그대로 이어져 오고 있다. 그 초기 디자인을 유지한 가장 최신 버전인 JUnit 3.8에 있는 문서에 나타난 JUnit의 핵심 클래스 구조에서도 여전히 3개의 클래스(Test Inteface가 그 연결역할을 해주기 위해서 들어갔지만)가 JUnit의 핵심인 것을 알 수 있다. 이 작은 핵심 클래스에 적용된 패턴들이란… ( ")!

 

- JUnit Cook’s Tour의 JUnit Patterns

 

JUnit의 정신은 심플함이다. 모든 개발자들에게 모든 상황에서 적용가능한 가장 최소한의 공통적인 기능만 제공한다는 것이 Kent Beck과 Erich Gamma의 JUnit에 대한 개발전략이다.

 

왜 그럴까? 그것은 처음 SUnit을 개발할 때부터 JUnit을 개발해 오는 지금까지 "개발자들이 자신의 환경을 직접 컨트롤할 수 있고 또 각 팀이 테스팅 프레임워크를 만들어 쓰는 것이 좋다(people to control their own environment, so he liked to have each team build the (testing) framework themselves)"는 철학을 가지고 있기 때문이다.

 

JUnit은 그 자체로 모든 것을 제공하지는 않고 오히려 그것을 쉽게 확장하고 자신의 프로젝트와 팀에 맡게 발전시킬 수 있도록 단순하고 유연한 모습을 유지하고 있는 것이다. JUnit의 사용하면서 종종 필요할지 모르는 일부 기능조차 extension이라는 별도의 패키지에 담아서 제공된다. 별로 사용하는 사람은 못 봤지만. 따라서 JUnit을 사용하는 개발자라면 적절히 그 기능을 확장하고 자신의 필요에 맞게 사용하는 작은 노력이 요구된다. 공개되어 있는 JUnit의 각종 extension과 addon은 적지 않다. 또 그것을 직접 확장해서 만드는 것도 매우 간단하다. JUnit을 직접 고치지 않아도 확장을 통해서 어떤 툴이나 IDE와도 손쉽게 연동할 수 있다.

 

JUnit을 잘 확장해서 사용한 좋은 예가 바로 스프링의 테스팅 프레임워크이다.

 

나는 개발자들이 이보다 더 나아가서 JUnit과 같은 테스팅 프레임워크를 직접 만들어보는 경험을 하는 것을 적극 권장한다. 물론 JUnit을 사용하지 말고 자신이 만든 것으로 대체하라는 말은 아니다. 뭐 못할 것도 없지만, IDE지원이 없으면 사용하기 불편할 것이다. 

 

JUnit과 같은 테스팅 프레임워크를 직접 개발해 보는 것이 주는 장점은 여러 가지이다. 잘 알려진 xUnit 스타일의 개발을 먼저 따라 해보는 것을 권하고 싶다. TDDBE 책은 xUnit 프레임워크를 파이썬을 사용해서 TDD 방식으로 직접 만드는 과정을 매우 잘 설명해주고 있다. 나는 TDDBE를 처음 봤을 때 xUnit 프레임워크를 맨땅에서 TDD 방식으로 만드는 것을 보고 입이 쩍 벌어졌다. 그 이전에 TDD를 좀 안다고 생각했었음에도 상상도 못 했던 것이다. 그래서 나에게 TDD의 정신을 가장 확실하고 명쾌하게 느끼게 해 준 것이 바로 그것이다. Kent Beck은 새로운 언어를 학습하면 먼저 xUnit을 만들어본다고 한다. 물론 TDD로. 그 과정에서 그 언어에 대한 좋은 감각을 익힐 수 있음이 분명하다.

 

xUnit을 만들어보는 것은 TDD의 학습 자체에도 매우 큰 도움이 된다. 또한 xUnit에 나타난 다양한 디자인/구현 패턴에 대한 이해와 적용훈련도 될 수 있다. 내가 스프링의 소스를 보면서 또는 Rod Johnson의 초기 J2EE 책을 보면서 느꼈던 패턴의 적용에 대한 매력을 사실 JUnit 하나에서 거의 그대로 느낄 수 있었다. 다음은 JUnit에 적용된 패턴의 스토리보드이다. GML로 작성되어 있다. TDD를 통해서 자연스럽게 만들어지는 패턴에 대한 감각을 익히는데도 최고이다. Pluggable Selector와 같은 자바개발자들에게는 최근에 나온 Implementation Pattern에서나 찾아볼 수 있는 패턴도 이미 11년 전에 JUnit에 적용되어서 사용되었다.

 

- JUnit Cook’s Tour의 JUnit Pattern Storyboard

 

어제 기선이에게 xUnit을 한번 TDD로 만들어보라고 했는데, 오후 반나절 만에 뚝딱 다 완성하고 그 과정까지 블로그에 다 공개했다. TDD의 특성상 글로만 쓰기는 좀 그래서 조만간 스크린캐스트로도 공개할 예정이라고 한다.

 

TDDBE에 나온 xUnit 예제는 매우 간결한 편이고 자바에 그대로 적용하기에는 언어적인 차이 때문에 달라질 부분이 있다. 물론 처음엔 그대로 해봐도 상관없겠지만, 나중에는 JUnit 코드를 보고 따라 하는 것이 좋겠다.

 

JUnit의 소스는 4.0 이전버전을 참조하면 좋다. 3.x만 해도 벌써 이런저런 복잡한 변화가 있으니 그 이전버전을 소스를 참조해 보면 좋을 것이다. 처음에는 그냥 따라 하는 것을 두려워할 필요는 없다. JUnit 2.0부터는 JUnit 자체에 대한 테스트 소스가 함께 공개되는데 어렵사리 구한 JUnit 1.0에는 테스트 코드가 없는 것이 좀 아쉽다. 먼저 가장 단순하게 구현한 JUnit 1.0을 2.0의 테스트 코드를 참조하고(거의 비슷하다) TDDBE에 나온 순서를 잘 따라서 유사한 방식으로 만들어보면 좋을 것이다. 그리고 JUnit이 2.0, 3.0으로 바뀌면서 리팩터링 되고 추가된 기능들을 history 문서를 잘 보면서 비교해서 보도록 하자. JUnit의 발전과정을 잘 살펴보면 왜 "test"로 시작하는 테스트 메서드를 작성하게 되었는지 또 테스트 메서드는 public으로만 작성해야 했는지를 알 수 있을 것이다.

 

JUnit 소스는 내가 본 가장 심플하고 아름다운 코드 중의 하나이다. 이토록 짧은 코드를 통해서 이렇게 많은 것을 배울 수 있도록 해준 것은 JUnit 뿐인 듯하다. 스프링이 그다음.

 

2.0부터의 소스는 http://sourceforge.net/project/showfiles.php?group_id=15278&package_id=12472 에서 찾을 수 있다. 1.0은 http://members.pingnet.ch/gamma/junit-10.zip 여기에서 구할 수 있다. JUnit Cook’s Tour는 JUnit의 구조와 그 패턴에 관한 가장 잘 설명된 문서이다. JUnit을 만들어보는데 많은 도움이 될 것이니 필독.

 

JUnit 스타일로 프레임워크의 개발을 어느 정도 해봤다면 (1-2시간 정도로 충분히 된다 싶으면) 이제는 자신만의 테스팅 프레임워크를 자기의 감각으로 만들어보는 것도 좋겠다. JUnit을 의식하지 않고 스스로 테스팅 프레임워크를 창조적으로 만들어보는 것도 좋은 훈련이다. JUnit의 디자인 결정을 싫어하는 사람도 있다. 예를 들면 매 테스트마다 새 인스턴스를 만드는 것 따위말이다. 자신만의 더 나은 아이디어나 스타일이 있다면 그렇게 만들어보고, JUnit과 비교해 보는 것도 좋겠다.

 

테스팅 프레임워크는 프레임워크 기반의 접근방법(Framework Based Approach)을 배울 수 있는 가장 간단하고 좋은 예라고 생각된다. 또한 계층화된 프레임워크 구조와 확장포인트(extension point)에 대해서도 여러 가지 전략을 연습해 볼 수 있고. 따라서 프레임워크 개발자라면 반드시 한 번쯤 만들어봐야 할 것이다. FBA는 사실 Rod Johnson이 그의 책에서도 여러 번 강조한 것이다. 항상 프레임워크 기반의 접근방법을 사용하라라는 그의 주장이 잘 담긴 것이 바로 스프링이다. 스프링의 극대화된 유연성과 수많은 확장포인트들은 스프링 사용자들에게 스프링을 FBA 스타일로 사용하도록 권장하고 있다.

 

JUnit은 4.0에 들어서 획기적인 변화를 가져왔다. Java5의 언어의 변화를 받아들여 좀 더 사용하기 편하고 단순한 프레임워크로의 변신을 하게 된다. 사실 그 변화는 매우 중대한 것인데, 그 이전의 JUnit의 모든 디자인과 구조를 바꾸었기 때문이다. 어노테이션의 적용은 언어의 특징을 매우 크게 바꾸는 결과를 가져왔다. 덕분에 JUnit을 사용하기는 좀 더 편해졌지만 기존 디자인은 대부분 버려야 했고, 프레임워크 자체는 매우 복잡해졌다. JUnit팀은 4.0을 개발하는 과정이 상당히 즐거운 것이라고 하긴 했지만 이전의 심플한 OO스타일이 잘 녹아있는 JUnit은 4.x에선 사라져 버렸다. (물론 3.8 스타일의 패키지는 여전히 포함되어 있다). JUnit 4.0으로 가면서 변한 것과 여전히 유지하고 있는 것이 무엇인지, 그 과정에서 배운 교훈과 고민은 무엇이었는지는 Kent Beck의 JavaOne 발표를 들어보기 바란다.

 

JUnit 4는 얼마 전 4.5가 릴리즈 되면서 매우 빠르게 발전하고 있다. 한동안 정체되어서 프로젝트가 죽은 게 아니냐는 이야기를 들었던 JUnit이 맞나 싶을 정도로 그 발전과 변화가 빠르다. 특히 4.4에서의 다양한 변신은 JUnit을 더욱 매력적인 방법으로 확장해서 사용할 수 있도록 도와주고 있다. 스프링의 JUnit 4 Test가 그 좋은 예다.

 

주말쯤 해서 자신만의 테스팅 프레임워크를 만들어보고 공개해 보는 것이 어떨까? 또는 같은 개발팀의 개발자들과 함께 짝프로그래밍으로 팀을 위한 테스팅 프레임워크를 만들어보는 것도 좋겠다.