[Junit] 테스트 작성: AAA(Arange-Act-Assert) 형식

AAA Type 테스트 작성

테스트는 이름 짓기부터 굉장히 중요하다. 자칫 잘 못 하면 Success 를 해도 어떤 뭐가 통과된 것인지 모를 때가 있다. 그렇기 때문에 준비-실행-단언 (AAA, Arrange-Act-Assert)을 타입으로 테스트를 작성하는 것은 일종의 룰이라고 할 수 있다. AAA Type 작성을 통해 조금 더 가시적이고 일관성있는 규칙의 테스트 이름을 지을 수 있다.

AAA(Arange-Act-Assert) 이용한 테스트 일관성 유지

이 글에서 간단하게 정리하려는 내용은 기본적으로 AAA 타입 테스트 명 작성 방법이다. 여기에 더해 @After 가 추가되어 AAAA 로 불리는 경우도 있다고 하는데, 중요한 것은 세 개의 A이다. 세 개의 A는 각각 아래와 같은 뜻으로 해석할 수 있다.

  • 준비(Arrange): 테스트 코드를 실행하기 전 시스템이 적절한 상태에 있는지 확인
  • 실행(Act): 테스트 코드 실행. 보통 단일 메서드 실행
  • 단언(Assert): 실행한 코드가 기대한 대로 동작하는지 확인.

여기에 추가적으로, 앞서 말했던 @After 가 추가될 수 있는데, 이 마지막 After 어노테이션은 테스트가 끝 난 사후를 뜻하며 테스트 실행 시 할당한 자원들을 정리해 다음 테스트에서 혼선이 발생하지 않도록 하는 역할을 수행한다. 테스트 완료는 정상 실행 확인에서 그치지 않고, 자원의 회수 및 정상적인 테스트 환경 유지까지를 목표로 한다는 의미라고 생각된다.

AAA vs GWT

여기까지 읽으며, BDD (Behavior Driven Development)에 대해 조금이라도 들어봤던 사람은 GWT(Given, When, Then) 과 무엇이 다른 것인지 궁금할 수 있다. 얄팍한 검색 실력으로 이곳 저곳을 찾아 본 결과로 둘은 크게 다르지 않다. 대다수 사람들이 Arrange 는 Given, Act 는 When, Assert 는 Then 과 대응된다고 느낀다고 한다. 실제로 영어권 개발자가 작성한 Test style 에 관련 짧은 칼럼에는 아래와 같이 적혀있다.

So, when I’m about to write tests, instead of thinking how I’m going to…

ARRANGE my test, I think what I’m GIVEN…
ACT in my test, I think WHEN something happens…
ASSERT the results, I think if that something happens THEN this is what I expect as the outcome.

그럼에도 불구하고 두 차이를 서술하자면, 역시 나의 얄팍한 지식과 Stack Exchange 글 Differences between Given When Then (GWT) and Arrange Act Assert (AAA)? 내용을 빌려 다음과 같이 정리할 수 있을 것 같다.

AAA는 조금 더 개발자 친화적인 테스트 스타일이며, 반대로 GWT는 비즈니스 친화적인 테스트 스타일이라는 것. 창고에 물건이 N개 있을 때, 사용자가 N개를 주문하면 N개가 배송되어야 한다 라는 것이 사용자 수준의 요구사항이라면 이를 만족시키기 위한 하위 레벨의 요구사항들이 가지처럼 연결되어 있을 것은 당연하다. 가령 예를 들자면, 창고에 물건이 N개 있을 때, N보다 작은 M개가 주문되면 M개를 배송하고, 남은 양은 N-M개 여야 한다 등의 프로그램 수준의 요구사항이 있겠다.

앞에서 설명한 것처럼 User-Level Requirement ← System-Level Requirement ← Programmer-Level Requirement 로 이어지는 요구사항의 관계 속에서 이를 테스트하기 위해서는 GWT 스타일이 선호되며, 단순히 특정한 메소드 하나를 테스트 하는 용도로는 AAA가 사용된다고 말한다. 즉, GWT는 요구사항 관계들 속에서 정의되지만 AAA는 단순히 Programmer-Level 에서 기능이 올바르게 동작하는가에 초점을 맞춘다는 것이다.

결론적으로, 나는 GWT의 Given과 AAA의 Arrange는 말 그대로 소프트웨어가 실행되며 주어지는 것, 즉 DOC(Depended On Component)들을 뜻하는데 Given은 조금 더 의존성이 높아 이를 끊기 위한 Mocking 이 많이 필요하고, Arrange는 Stub이나 Dummy로도 해결할 수 있는 간단한 것들이라 이해했다. 스터디에서도 이 주제로 많은 얘기를 했던 것 같은 기억이 난다.

테스트 관리

앞서 테스트 스타일에 대해 간략하게 정리를 했다. 중요한 것은 GWT, AAA 모두 단순히 메서드를 테스트하는 것이 아니라 객체가 수행할 동작이 무엇인지 생각해보고, 이를 메서드로 나누어 테스트 할 수 있도록 설계하는 능력을 필요로 한다는 것이다.

이런 설계 역량을 얻기 위해서는 물론 다양한 테스트 코드 작성 경험을 갖춰야 한다. 한 가지 확실한 것은 다양한 책에서 공통적으로 말하는 단일 목적 테스트를 지향해야 한다는 것이다.

단일 목적 테스트란 다수의 케이스를 별도의 Junit 테스트로 분리해 각각 따로 검증하는 것을 말한다. 한 개의 메소드라도 General Case, Edge Case, Corner Case 등 다양한 상황을 고려해 테스트하는 것을 말하는데, 사실 생각해보면 당연한 것이다.

단언이 실패했을 때는 실패한 테스트 이름이 표시되기 때문에 어떤 동작에서 문제되는지 확인이 가능하다. 세부 케이스들을 많이 만들어 놓을 수록 실패 오류를 해독하는 데 필요한 시간을 줄일 수 있다. 다르게 말하면 어떤 부분이 영향을 끼쳤는지 복잡한 해석이 필요 없어진다는 뜻이다. 여기에 지속적인 노력이 추가된다면, 조금 더 과장을 보태 모든 케이스가 실행되었음을 보장할 수 있는 경지에 오르게 되는 것.

이 정도가 되면 개발자들끼리 공유해야하는 산출물이 비약적으로 감소할 것이다. 주석과 더불어 단위 테스트가 클래스에 대한 지속적이고 믿을 수 있는 문서 역할을 대신해주기 때문인데, 이는 코드 자체가 하나의 문서다 이놈아 라는 개발계 격언과도 어느 정도 일맥상통하니 더욱 더 흥미로운 경험이 될 것이다.

정리

Test style, Test type 은 작성하는 사람마다 조금씩 달라질 수 있다. 그러나 본질은 같다. 기회가 되면 Legacy 코드들에 작성된 테스트들을 살펴보고, 나아가 내 스타일을 찾아가보는 시간을 가져보면 좋을 것 같다.

Updated:

Leave a comment