2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【SpringBoot】【JUnit】Controller層の単体テスト

Posted at

サンプルコード

Controller層の単体テストを行うクラスを以下のように実装します。
作成したjavaファイルはテストディレクトリ下に配置します。

1. Controller層だけをテストするためのアノテーションをつける
2. MockMvc(疑似HTTPクライアント)を用意する
3. Serviceをモック化し、Controllerクラスに自動注入する
4. JSON変換用 の ObjectMapper を用意する(Java ⇄ JSON)
5. 任意のテストメソッド

実装例:

.java
// 1. Controller層だけをテストするためのアノテーション
@WebMvcTest(BookController.class)
class BookControllerTest {

    // 2. MockMvc(疑似HTTPクライアント)を用意する
    @Autowired
    private MockMvc mockMvc;

    // 3. Serviceをモック化し、Controllerクラスに自動注入する
    @MockBean
    private BookService service;

    // 4. JSON変換用 の ObjectMapper を用意する(Java ⇄ JSON)
    @Autowired
    private ObjectMapper objectMapper;

    // 5. 任意のテストメソッド

    // GETリクエストのテスト:
    @Test
    void testGetBooks() throws Exception {

        Book b = new Book();
        b.setId(1L);
        b.setTitle("Effective Java");
        b.setAuthor("Joshua Bloch");
        b.setPrice(5500);

        Page<Book> page = new PageImpl<>(List.of(b), PageRequest.of(0,1), 1);

        Mockito.when(service.list(Mockito.any(), Mockito.any())).thenReturn(page);

        mockMvc.perform(get("/api/books"))
                .andExpect(status().isOk()) // ステータスコード200
                .andExpect(jsonPath("$.content[0].title").value("Effective Java"));
    }

    // POSTリクエストのテスト
    @Test
    void testCreateBook() throws Exception {

        Book newBook = new Book();
        newBook.setId(2L);
        newBook.setTitle("JUnit入門");
        newBook.setAuthor("山田太郎");
        newBook.setPrice(1800);

        Mockito.when(service.create(Mockito.any())).thenReturn(newBook);
        String json = objectMapper.writeValueAsString(newBook);
        mockMvc.perform(post("/api/books")
                        .contentType(MediaType.APPLICATION_JSON) 
                        .content(json))                         
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.title").value("JUnit入門")) 
                .andExpect(jsonPath("$.price").value(1800));
    }

    // バリデーションチェックのテスト
    @Test
    void testCreateBook_TitleBlank_BadRequest() throws Exception {

        BookRequest invalidReq = new BookRequest(
                " ", 
                "山田太郎",
                1800
        );

        String json = objectMapper.writeValueAsString(invalidReq);

        mockMvc.perform(post("/api/books")
                        .contentType(MediaType.APPLICATION_JSON)  
                        .content(json))                           
                .andExpect(status().isBadRequest());
    }

}

1. Controller層だけをテストするためのアノテーション

.java
@WebMvcTest(BookController.class)
class BookControllerTest

@WebMvcTestをつけることで、Spring MVC を最小構成で起動し、Service や Repository などはロードしないように設定する。Controllerの動作とHTTPレスポンスの動作を確認するために使用する。


2. MockMvc(疑似HTTPクライアント)を用意する

.java
@Autowired
private MockMvc mockMvc;

MockMvc は Spring MVC を模した「疑似HTTPクライアント」。
実際にサーバーを起動せずに HTTP リクエストを送ってテストできる。


3. Serviceをモック化し、Controllerクラスに自動注入する

.java
@MockBean
private BookService service;

@MockBean を付けると Spring が BookService のモックを自動生成し、
Controller に注入してくれる。Service は実際の処理を行わず、テスト用の動作だけを返す。


4. JSON変換用 の ObjectMapper を用意する(Java ⇄ JSON)

.java
@Autowired
private ObjectMapper objectMapper;

MockMvc でPOSTする際に JavaオブジェクトからJSONに変換する必要があるため、予め用意しておく。


5. 任意のテストメソッド

GETリクエストのテスト:

.java
// --------------------------------------------------------------
// GET /api/books のテスト(一覧取得)
// --------------------------------------------------------------
@Test
void testGetBooks() throws Exception {

    // ---- ① テスト用の Book を1件準備 ----
    Book b = new Book();
    b.setId(1L);
    b.setTitle("Effective Java");
    b.setAuthor("Joshua Bloch");
    b.setPrice(5500);

    // ---- ② Page<Book> をテスト用に作成 ----
    // PageImpl を使って 1 件だけ入ったページを生成する
    Page<Book> page = new PageImpl<>(List.of(b), PageRequest.of(0,1), 1);

    // ---- ③ Service の戻り値をモック化 ----
    // BookService.list(...) が呼ばれたら、上で作った page を返す
    Mockito.when(service.list(Mockito.any(), Mockito.any())).thenReturn(page);

    // ---- ④ MockMvcでGETリクエストを実行 ----
    mockMvc.perform(get("/api/books"))
            .andExpect(status().isOk()) // ステータスコード200
            // JSONの中身を検証 → $.content[0].title が "Effective Java" であるか?
            .andExpect(jsonPath("$.content[0].title").value("Effective Java"));
}

POSTリクエストのテスト:

.java
// --------------------------------------------------------------
// POST /api/books のテスト(新規登録)
// --------------------------------------------------------------
@Test
void testCreateBook() throws Exception {

    // ---- ① Serviceが返すテスト用Bookを作成 ----
    Book newBook = new Book();
    newBook.setId(2L);
    newBook.setTitle("JUnit入門");
    newBook.setAuthor("山田太郎");
    newBook.setPrice(1800);

    // ---- ② create() が呼ばれたら newBook を返すように設定 ----
    Mockito.when(service.create(Mockito.any())).thenReturn(newBook);

    // ---- ③ リクエストボディに送る JSON を作成 ----
    // ObjectMapper により Javaオブジェクト → JSON文字列 に変換
    String json = objectMapper.writeValueAsString(newBook);

    // ---- ④ POSTリクエストを実行 ----
    mockMvc.perform(post("/api/books")
                    .contentType(MediaType.APPLICATION_JSON) // JSONを送る宣言
                    .content(json))                         // ボディ部分にJSONを渡す
            .andExpect(status().isOk())                    // ステータス200
            .andExpect(jsonPath("$.title").value("JUnit入門")) // JSON結果の検証
            .andExpect(jsonPath("$.price").value(1800));
}

バリデーションチェックのテスト:

.java
// --------------------------------------------------------------
// POST /api/books のテスト(バリデーションチェック)
// --------------------------------------------------------------
@Test
@DisplayName("title が空文字の場合、400 Bad Request になること")
void testCreateBook_TitleBlank_BadRequest() throws Exception {

    // ---- ① バリデーションに引っかかる入力データを作成する ----
    // BookRequest の title が空(空白のみ)なので、@NotBlank に違反する
    // → Controller メソッドの @Valid によってバリデーションエラーとなる
    BookRequest invalidReq = new BookRequest(
            " ",          // ← @NotBlank によって「空白のみ」は無効と判断される
            "山田太郎",
            1800
    );

    // ---- ② リクエストボディに使う JSON を作成(Java → JSON) ----
    // MockMvc で POST するために JSON 形式の文字列に変換する
    String json = objectMapper.writeValueAsString(invalidReq);

    // ---- ③ /api/books に対して POST リクエストを送る ----
    // title が空白のため、Controller 側の @Valid によって自動的に 400 (Bad Request) が返る
    mockMvc.perform(post("/api/books")
                    .contentType(MediaType.APPLICATION_JSON)  // JSON を送ると宣言
                    .content(json))                           // JSONデータ本体
            .andExpect(status().isBadRequest());              // 期待値:400 Bad Request

    // ----------------------------------------------------------
    // ※補足
    // JSONのエラー内容を細かく確認したい場合は jsonPath を使ってチェック可能
    // 例:
    // .andExpect(jsonPath("$.errors[0].field").value("title"));
    // .andExpect(jsonPath("$.errors[0].message").exists());
    // ----------------------------------------------------------
}
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?