Blog Posts

Kotlin 테스트 코드 결함 Intellij 플러그인 개발기

링크모은

개발을 하다 보면 코드의 신뢰성을 검증하거나 내용을 전달하는 목적으로 테스트 코드를 많이 작성하게 되는데요. 링크모은 작성하는 것보다 단위 테스트(unit test) 코드를 작성하는 데에 가장 많은 시간을 투여하게 됩니다. 단위 테스트는 하나의 기능만 테스트하는 것이기 때문에 영향을 받는 부분이 매우 적으며, 비용이 저렴하기 때문입니다.

단위 테스트에서 반복되는 보일러 플레이트 코드

팀 내에서 이러한 테스트 코드를 Kotlin 스타일로 더 쉽게 작성하기 위해 KoTest라는 테스트 프레임워크와 모킹(mocking)을 위한 mockk 라이브러리를 이용하고 있습니다.

테스트 코드 작성에 많이 알려진 Given-When-Then Pattern도 이용하고 있는데요.
대부분 아래와 같은 흐름으로 작성되게 됩니다.

위의 테스트 코드는 제가 이전까지 경험해 온 팀들도 대다수 사용하는 패턴으로 테스트 대상 시스템(system under test)를 이루는 의존성을 모킹(mocking)하여 격리시킨 뒤 온전하게 테스트 대상 시스템만 테스트하는 단위 테스트 방식입니다.

링크모은 코드를 작성하기 위해서는 given 절에서 수행되는 내용이 아래처럼 항상 반복되는 것을 알게 됩니다.

1.테스트 대상 시스템 (SUT)을 제외한 의존성을 모킹(mocking)한다.
2.SUT에 대상 의존성을 주입한다.

즉, 우리는 단위 테스트를 작성할 때 위 패턴을 반복해서 작성하게 됩니다. 따라서 이렇게 반복되는 패턴을 자동화할 필요성이 있다고 느껴 여러 Intellij 플러그인을 찾게 되었습니다.

그 중, TestMe라는 플러그인을 찾았으나 아쉽게도 Kotlin 그리고 Kotest 를 별도로 지원하지는 않았습니다. 그래서 별도로 개발을 진행해야 겠다는 생각을 가지게 되었고, 10월 초에 개발을 진행하게 되었습니다.

플러그인 개발기

Intellij 내부에서 우리가 코드를 작성하거나, 파일을 생성하기 위해 단축키인(Cmd + N)을 누르는 과정 모두 하나의 Action으로 취급됩니다. 기존에 우리가 테스트 파일을 쉽게 생성하기 위해 만드는 단축키인 (Cmd + Shift + T) 조차도 Create Test라는 하나의 행위(Action)으로 취급됩니다.

따라서, 기본적으로 제공하는 Action이 있다면 상속(extend)하여, 약간 수정하면 좀 더 수월하게 개발할 수 있는데요. Intellij에서는 이미 CreateTestAction이라는, 테스트를 생성할 때 발생하는 Action 기본 동작들을 다루는 클래스를 제공하고 있습니다. 따라서, 저 또한 아래와 같이 CreateTestAction Class를 상속받아 개발을 진행하였습니다.

링크모은 생성하는 단축키인 행위(action)에 제 커스텀 이벤트를 등록시키기 위해서는, Intellij 내장 클래스인 GoToTestOrCodeHandler()에 위에서 생성한 CustomHandler를 이용하여 코드를 실행할 수 있도록 등록해야 합니다.

Kotlin 파일 분석하기

(들어가기에 앞서, 이 부분에서는 간단하게 문맥을 잘 이해할 수 있을 정도의 코드만 설명할 예정입니다.)

이제 Handler는 잘 등록을 했고, 우리가 원하는 테스트 파일을 만들기 위해서는 우리가 현재 마우스를 올리고 있는 파일에 대한 정보를 분석할 수 있어야 합니다. Kotlin 파일은 Intellij 내에서 KtFile 형태 (Type)으로 분류됩니다. KtFile Type에는 클래스 내부 정보를 쉽게 알 수 있도록 몇몇 메서드들을 지원합니다. 그래서, 해당 메서드를 이용하여 좀 더 수정하여 Kotlin 파일을 분석하는 저만의 Parser 클래스를 작성하였습니다.

여기서는 클래스 이름 혹은 메서드와 같은 현재 클래스에 대한 정보를 해석할 수 있는 기능을 제공하게 됩니다. 우리는 여기서 getProperties() 함수를 통해 우리가 원하던 Class 내부 의존성을 파악할 수 있게 됩니다.

테스트 파일 생성

이제 분석한 정보를 앞으로 클래스 메타 데이터(ClassMetaData)라고 표현하겠습니다. 이 클래스 메타 데이터(ClassMetaData)를 기반으로 아까 위에서 작성했던, 테스트 대상 시스템(SUT)에 모킹한 의존성을 넣는 코드를 작성해 봅시다.

테스트 파일을 생성할 때 아무런 규격이 없이 단순 문자열로만 파일을 생성하게 되면, 이후 오픈소스로 기여(Contribution)받게 되면 유지보수가 힘들어지고 규칙성 있게 코드를 작성하기 힘들어질 수 있어 Builder 라이브러리를 찾아보게 되었습니다.
팀에서 추천받은 KotlinPoet이라는 FileBuilder를 이용했는데, 아래 코드와 같이 빌더 방식으로 Kotlin 파일을 생성할 수 있습니다.

위 라이브러리를 이용하여 아래와 같이 테스트 파일을 생성하는 코드를 작성했습니다. 코드를 모두 보여주기에는 너무 길어져서 테스트 코드의 검증부 부분만 보여드리겠습니다.
TestClassTest라는 클래스는 의존성으로 List Type의 ages 변수를 가지고 있는 경우 아래 then 절의 결과와 같이 테스트 파일이 생성됩니다. 지금까지 우리가 위에서 언급했던 단위 테스트(unit test)에서의 반복되는 부분을 쉽게 생성할 수 있도록 코드로 간략하게 확인해 보았습니다. 이제 실질적으로 어떻게 사용하는지 알아봅시다

마켓에 배포하기

플러그인을 마켓에 배포하려면 빌드하여 플러그인을 .jar 또는 .zip 파일로 만들어야 합니다.