Spring Boot のコントローラーを MockMvc でユニットテストするサンプルコード

## 今回の環境

- Java 11 (OpenJDK 11.0.2)
- Spring Boot 2.2.2
- Thymeleaf 3.0.11
- JUnit 5.5.2
- Hamcrest 2.1

## テスト対象のコントローラーと Thymeleaf テンプレート

```java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class FooBarController {

  @GetMapping("/")
  public ModelAndView topPage(ModelAndView mav) {
    mav.setViewName("index");
    mav.addObject("userName", "Alice");
    return mav;
  }
}
```

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>My App</title>
</head>
<body>
<p id="user-name" th:text="${userName}"></p>
</body>
</html>
```

## コントローラーをテストするクラス

```java
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.test.web.servlet.MockMvc;

import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

@SpringBootTest
@AutoConfigureMockMvc
public class FooBarControllerTest {

  @Autowired
  private MockMvc mockMvc;

  // ユーザーエージェント文字列
  private static final String USER_AGENT =
    "Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X) " +
    "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 " +
    "Mobile/15E148 Safari/604.1";

  @Test
  public void testTopPage() throws Exception {
    this.mockMvc.perform(
      // GET メソッドでアクセス
      get("/")
      // リクエストヘッダを指定
      .header(HttpHeaders.USER_AGENT, USER_AGENT))
      // HTTP ステータスコードをテスト
      .andExpect(status().is2xxSuccessful())
      // ビュー名をテスト
      .andExpect(view().name("index"))
      // モデルの属性をテスト
      .andExpect(model().attribute("userName", "Alice"))
      // Content Type をテスト
      .andExpect(content().contentType("text/html;charset=UTF-8"))
      // ページに指定したテキストが含まれるかテスト
      .andExpect(content().string(containsString("Alice")));
  }
}
```

## 参考資料

- [Testing - Spring Framework Documentation](https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/spring-framework-reference/testing.html)
- [AutoConfigureMockMvc \(Spring Boot Docs 2\.2\.2\.RELEASE API\)](https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/api/org/springframework/boot/test/autoconfigure/web/servlet/AutoConfigureMockMvc.html)
- [MockMvc \(Spring Framework 5\.2\.2\.RELEASE API\)](https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/test/web/servlet/MockMvc.html)
- [MockMvcRequestBuilders \(Spring Framework 5\.2\.2\.RELEASE API\)](https://docs.spring.io/spring/docs/5.2.2.RELEASE/javadoc-api/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.html)
- [MockMvcResultMatchers \(Spring Framework 5\.2\.2\.RELEASE API\)](https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/test/web/servlet/result/MockMvcResultMatchers.html)
- [Matchers \(Hamcrest 2\.1 API\)](http://hamcrest.org/JavaHamcrest/javadoc/2.1/org/hamcrest/Matchers.html)