前回実装したClean Architecture APIのUnitテストを書いていきます。
目次
JUnit
JUnitとはJavaで開発されたプログラムにおいてユニットテストの自動化を行うためのフレームワークです。
よく使いそうなアノテーション
@Test
メソッドに付与することでJUnitにテストメソッドであることを認識します。
@DisplayName
テストの表示名を設定できます。
@BeforeEach
付与されたメソッドは、各テストメソッド実行前に@BeforeEachアノテーションがついたメソッドが実行されます。JUnit 4の@Beforeと同じです。
@Disabled
@Disabled はクラスまたはメソッドに付与してテストを実行させないようにすることができます。JUnit4における@Ignoreに相当します
JUnit5のアノテーション一覧は以下の公式で見ることができます。
MockK
MockKとは Kotlin用のモックライブラリです。

every
everyを使うと特定のモックインスタンスが呼ばれた時に指定した値を返却します。
verify
verifyを使うとメソッドが指定した引数で呼び出されたかを確認できます。
よく使いそうなアノテーション
@MockK
モックインスタンスとしてインジェクションしたい場合に使用します。
@SpyK
Spy用のインスタンスとしてインジェクションしたい場合に使用します。
Spyはオブジェクトを実際のコードで動かしつつ、メソッドの引数や呼び出し回数、戻り値などを検証するために使用します。
注意点としては、アノテーションを利用して初期化する際には@Spyk var hoge = Hoge()のようにvarかつインスタンス生成する必要があります。
@InjectMockKs
該当オブジェクトのもつ属性に対してインジェクトしたい場合に使用します。
ControllerのUnitテスト
@ExtendWith(SpringExtension::class)でSpring拡張機能をインクルードしていましたが、調べたら@SpringBootTestアノテーションを使用している場合は@ExtendWith(SpringExtension::class)を付与する必要はなくなったようです。
参考:https://github.com/spring-projects/spring-boot/issues/13739
・TaskControllerTest.kt
HTTPメソッドへのテスト
MockMvcBuilders.standaloneSetup()でControllerの動作を再現するための準備をします。
参考:https://terasolunaorg.github.io/guideline/5.4.1.RELEASE/ja/UnitTest/ImplementsOfUnitTest/UsageOfLibraryForTest.html#mockmvc
@BeforeEachアノテーションを付けて、全ての@Testの前に実行させます。以降、このmockMvcインスタンスを利用して、仮想のリクエストを発生させテストを実行します。
今回はテスト対象のTaskControllerを指定して、mockMvcを生成しています。
テストしたいPath(今回の場合はGET /api/tasks)を指定し、andExceptメソッドでレスポンスのテストを行います。
今回はHTTPステータスコードのテストなのでstatus()を使います。ステータスコード200はstatus().isOkでテストできます。代表的なステータスコードは以下の通りです。
- 200: status().isOk()
- 308: status().isPermanentRedirect()
- 404: status().isNotFound()
- 403: status().isForbidden()
- 503: status().isServiceUnavailable()
あとはcontent()でレスポンスの形と中身を見ています。今回はREST APIなのでJSON形式であることJSONの中身が正しいことをアサートしています。
また、Controllerないのメソッドにおいて、該当のuseCaseメソッドが呼ばれたこともテストしています。
ドメインからJSONへの変換テスト
ControllerではUseCaseから返ってきたドメインをレスポンスの形であるJSONに変換しているため、そのテストも行っています。
今回は各ドメインにtoJson()というメソッドを生やしているので、そのメソッドを実行してちゃんとドメインからJSONに変換されているかをアサートしています。
assertEquals()で値が等しいかを確認しています。左が期待値で右が実測値を入れます。
UseCaseのUnitテスト
UseCaseのテストではPortのメソッドを呼び出して、その返り値が正しいかをアサートしています。今回は簡素なAPIなので特にUseCaseでロジック挟んでおらず、シンプルなUnitテストになっています。
・TaskUseCaseTest.kt
GatewayのUnitテスト
GatewayではDriverメソッドを呼び出し、その返り値をアサートしています。またGatewayではDriverで受け取ったプリミティブなJSONオブジェクトをドメインに変換する処理をしているため、変換メソッドのテストも追加しています。
・TaskGatewayTest.kt
MockKでlateinitプロパティが初期化されない問題
springのMockKだとうまくいくのにMockKだと以下のエラーが出る問題がありました。
調べてみるとinitメソッドで解決できそうでしたので、実際やってみたらうまくいきました。
参考:https://github.com/mockk/mockk/issues/546
以下のように@BeforeEachを追加するだけです。テスト実行前にMockKAnnotations.initでモックインスタンスをインジェクションすることで解決できます。