Spring Bootの結合テスト
今回も一般的なTODOアプリのREST APIに対する単体テストをする想定とします。* こんなAPI
テストを書くときの瞬発力を上げるためのまとめなので、アノテーションの詳細は深くは書きません。ご了承ください。
環境は、Java 17, Spring Boot 3.x.x, MyBatisを使用しています。
Service と Repositoryの結合テスト
ここではServiceとRepositoryを繋いだ状態でServiceのメソッドを実行してテストします。
@SpringBootTest
は主に結合テストを行う際に利用するアノテーションです。
単体テストレベルで使うと時間に長くなってしまうので、使うときには注意が必要です。
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@Sql("TodoServiceTest.sql")
@Transactional
class TodoServiceTest(){
@Autowired
TodoServiceImpl todoService;
@Test
void 指定したIDのTodoが取得できること(){
Todo todo = todoService.findById(1);
assertThat(todo.getTitle()).isEqualTo("結合テスト");
}
}
今回はServiceからRepositoryの結合テストなのでwebEnvironment = WebEnvironment.NONE
を指定して組み込みWebサーバの起動はされません。
Serviceの単体テストを行った時にはRepositoryをモックして実行していましたが、
今回は実際にRepositoryまで処理を送って欲しいのでモックしていないということを理解しておくと良いです。
Repository層へのデータアクセスがあるため、テストデータの作成、テスト後のロールバックが必要になります。
この役割を果たすために、@Sql
と@Transactional
を使います。
Controller と Service と Repositoryの結合テスト
最後にControllerからリクエストを送信し、Service→Repositoryへ処理を行えるかをテストします。
Controller、Service、Repositoryを通したテストなので、実際にユーザーがアプリケーションを使う処理に限りなく近いです。
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
@Sql(TodoControllerTest.sql)
public class TodoControllerTest(){
@Autowired
private MockMvc mockMvc;
@Test
public void Todoの一覧が表示できること() throws Exception {
mockMvc.perform(get("/todo/list"))
.andExpect(content(string(containsString("結合テスト1"))))
.andExpect(content(string(containsString("結合テスト2"))))
.andExpect(content(string(containsString("結合テスト3"))));
}
}
@AutoConfigureMockMvc
以外はすでに解説しているので、このアノテーションのみ解説します。
このアノテーションはMockMvcオブジェクトを利用する時に使用します。
MockMvcを使うとサーバにデプロイすることなく、動きを再現してくれます。
つまり、MockMvcを使ったテストが失敗する場合、原因がアプリケーションに限定されることになります。
よってテストの関心が Controller〜Service〜Repository のみに絞ることができます。
まとめ
単体テストでも結合テストでも Junit5・Mockito を使用するので、テストのやり方自体は大きくは変わらないはずです。
利用するアノテーションとどこをMockするかに注意して、本当にやりたいテストになっているかに注意する必要があると感じました。
今後は Junit5のAssertion と MockMvc のよく使うメソッド周りをおさらいしてまとめていきたいと思います。
参考書籍 - プロになるためのSpring入門 ゼロからの開発力養成講座
私はエンジニアになって半年もないですが、学習時にはこんないい書籍なかった。。。
もっと早く出して欲しかったと切実に思うくらい、この書籍には助けられてます。
Discussion