Upgrade to Pro — share decks privately, control downloads, hide ads and more …

今こそ知りたいSpring Test / Spring Fest 2020

Ryo Shindo
December 17, 2020

今こそ知りたいSpring Test / Spring Fest 2020

Spring Fest 2020 Beginner Track
https://springfest2020.springframework.jp/

Ryo Shindo

December 17, 2020
Tweet

More Decks by Ryo Shindo

Other Decks in Programming

Transcript

  1. 1
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    今こそ知りたいSpring Test
    Spring Fest 2020
    Acroquest Technology株式会社
    進藤 遼(@shindo_ryo)

    View full-size slide

  2. 自己紹介
    • 進藤 遼
    • Acroquest Technology株式会社
    • 日本Springユーザ会 スタッフ
    • Twitter: @shindo_ryo
    • 好きなSpring Projectは
    Spring Cloud Sleuth
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 2

    View full-size slide

  3. 目次
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 3
    1. Spring Testの基礎
    2. モックテスト
    3. DBテスト
    4. Spring Webテスト
    5. Spring Bootテスト
    6. その他

    View full-size slide

  4. Spring Testの基礎
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 4

    View full-size slide

  5. Spring Testとは
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 5
    1. Springアプリケーションに対するインテグレーションテストを
    サポートするモジュール
    2. JUnit, TestNGといったテスティングフレームワークと連携する
    ※デフォルトでJUnit 5
    3. Spring MVCのテスト、DBテストなどを容易にする
    ユーティリティを多数提供

    View full-size slide

  6. Spring Testのインストール
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 6

    org.springframework.boot
    spring-boot-starter-test
    test

    デフォルトで設定済み

    View full-size slide

  7. SpringのDIの仕組み
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 7
    DIコンテナ
    (ApplicationContext)
    Bean Bean
    使う
    new
    new
    依存オブジェクトを注入

    View full-size slide

  8. SpringのDIの仕組み
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 8
    @Service
    public class FooService {
    private final BarService barService;
    public FooService(BarService barService) {
    this.barService = barService;
    }
    public String foobar() {
    return "foo" + barService.bar();
    }
    }
    @Service
    public class BarService {
    private final MessageSource messageSource;
    public BarService(MessageSource messageSource) {
    this.messageSource = messageSource;
    }
    public String name() {
    return messageSource.getMessage(
    "name", null, Locale.getDefault());
    }
    }
    DIコンテナが依存オブジェクトを注入

    View full-size slide

  9. 通常のユニットテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 9
    public class FooServiceTest {
    FooService service;
    @BeforeEach
    void beforeEach() {
    service =
    //何らかの方法で初期化
    }
    @Test
    void testHello() {
    assertEquals("Hi, Spring Fest 2020", service.hello());
    }
    }

    View full-size slide

  10. Spring Testを使わないと・・・
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 10
    1. 全てのインスタンスを自前でnew
    ➢ controller層からrepository層まで統合しようとすると
    非常に多くのBeanが必要になる
    2. 正しくDIできることをテストできない
    ➢ Beanが不足、または重複していても気づけない

    View full-size slide

  11. Spring Testを使うと・・・
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 11
    @ExtendWith(SpringExtension.class) ・・・①
    @ContextConfiguration( ・・・②
    locations = “classpath:/application-context.xml”)
    public class FooServiceTest {
    @Autowired ・・・③
    FooService service;
    @Test
    void testHello() {
    assertEquals("Hi, Spring Fest 2020",
    service.hello());
    }
    }
    ①JUnitとSpring Testを
    連携させる
    ②ApplicationContextの
    設定ファイルを指定
    (classesでJava Configも
    指定可能)
    ③テスト対象Beanを取得

    View full-size slide

  12. Spring Bootの場合
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 12
    @SpringBootTest
    public class FooServiceTest {
    @Autowired
    FooService service;
    @Test
    void testHello() {
    assertEquals("Hi, Spring Fest 2020",
    service.hello());
    }
    }
    @SpringBootApplicationがついたクラスを探索し、
    設定を自動的に読み込む。
    ※@ExtendWith(SpringExtension.class)は
    @SpringBootTestの中で指定されている。
    (Boot 2.1~)

    View full-size slide

  13. Spring TestContextフレームワーク
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 13
    SpringExtension TestContextManager
    TestContext
    テストクラスと
    ApplicationContextを
    セットにして管理
    ApplicationContext
    テストクラス
    @Autowired
    FooService service;
    TestExecutionListener
    use
    create
    Spring Bean
    テストコードの設定に対応
    するApplicationContextを
    ロード
    依存オブジェクトの注入と
    いった、テストの前処理・
    後処理を実行
    ApplicationContextは
    キャッシュされて使い回される

    View full-size slide

  14. テスト実行フロー
    Copyright © Acroquest Technology Co., Ltd. All rights reserved.
    14
    テストクラスのロード
    ApplicationContextの初期化
    テストクラスにSpring Beanを注入
    各テストメソッドを実行
    SpringExtension
    @Test
    JUnit

    View full-size slide

  15. スライステスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 15
    • 全てのBeanを初期化するには時間がかかる
    • テスト対象に必要なBeanのみを初期化したい
    →スライステスト
    @WebMvcTest
    @WebFluxTest
    @JsonTest
    @RestClientTest
    @WebServiceClientTest
    @DataJpaTest
    @DataCassandraTest
    @JdbcTest
    @DataJdbcTest
    @DataLdapTest
    @DataMongoTest
    @DataNeo4jTest
    @DataR2dbcTest
    @DataRedisTest
    @JooqTest
    Boot

    View full-size slide

  16. モックテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 16

    View full-size slide

  17. Mockito連携
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 17
    1. spring-boot-starter-testでは、デフォルトでMockitoを使った
    Beanのモック化機能が提供
    2. @MockBean / @SpyBean でBeanをモック化し、
    振る舞いを変えることができる
    FooService
    BarService BarService
    @MockBean

    View full-size slide

  18. @MockBean / @SpyBean
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 18
    @SpringBootTest
    public class FooServiceTest {
    @Autowired
    FooService service;
    @MockBean
    BarService barService;
    @Test
    void testHello() {
    Mockito.when(barService.name()).thenReturn("Mocked Response");
    assertEquals("Hi, Mocked Response", service.hello());
    }
    }
    フィールドにアノテーションを
    つけることで、Beanが自動的に
    モック化される(@SpyBeanも同様)
    Mock化された振る舞いを指定

    View full-size slide

  19. @MockBean / @SpyBean
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 19
    @SpringBootTest
    @MockBean(BarService.class)
    public class FooServiceTest {
    @Autowired
    FooService service;
    @Autowired
    BarService barService;
    @Test
    void testHello() {
    Mockito.when(barService.name()).thenReturn("Mocked Response");
    assertEquals("Hi, Mocked Response", service.hello());
    }
    }
    クラスアノテーションでも指定可能
    その場合は@Autowiredで注入する

    View full-size slide

  20. Q. ApplicationContextの起動回数は?
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 20
    @SpringBootTest
    public class BarServiceTest {
    @Autowired
    BarService service;
    @MockBean
    MessageSource messageSource;
    @Test
    void testBar() {
    // 省略
    }
    }
    @SpringBootTest
    public class FooServiceTest {
    @Autowired
    FooService service;
    @MockBean
    BarService barService;
    @Test
    void testHello() {
    // 省略
    }
    }
    モック化する
    Beanが異なる

    View full-size slide

  21. @MockBeanと実行時間
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 21
    A. 2回
    ⇒起動回数が増え、実行時間が遅くなりがち
    ApplicationContext ApplicationContext
    FooService BarService
    MessageSource
    FooService
    MessageSource
    BarService
    TestContext(FooServiceTest) TestContext(BarServiceTest)
    ApplicationContextが異なるため、
    キャッシュが使われない
    モック化されたBeanは
    モックでないBeanとは
    別のもの扱いとなる

    View full-size slide

  22. モックテストでも遅くならないようにする方法
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 22
    1. 各テストクラスでモック対象のクラスを完全に同一にする
    • 共通のJava Configを作って@ContextConfigurationで指定
    • 一つでも違う部分があるとアウト
    2. @MockBean/@SpyBeanを使わない
    • モックを使うテストではSpring Testを使わない
    • モッククラスを自作して、テスト中は@Primaryで差し替え
    @Service
    @Primary
    public class MockBarService { }

    View full-size slide

  23. DBテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 23

    View full-size slide

  24. DBテストのフロー
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 24
    テストデータのセットアップ
    テストの実行
    更新後のデータの検証
    ロールバック / テストデータの破棄
    テストデータの状態を一定に保つことで
    テストのべき等性を担保する

    View full-size slide

  25. テストデータのセットアップの2つの方法
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 25
    ① schema.sql / data.sql をクラスパスに配置する
    • DataSourceの初期化の段階で自動的に実行される
    • テストクラスごと、テストメソッドごとのような実行サイクルはできない
    ② テストクラス、テストメソッドに@Sqlを指定する
    • 任意のSQLファイルを読み込み実行する
    • テストメソッドの前後で実行させることができる

    View full-size slide

  26. @Sql
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 26
    @DataJpaTest
    @Sql(scripts = "classpath:/employee.sql",
    executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
    public class EmployeeRepositoryTest {
    @Autowired
    EmployeeRepository repository;
    @Test
    void testFind() {
    Employee employee = repository.findById(1L).get();
    assertEquals("shindo", employee.getName());
    }
    }
    TRUNCATE TABLE employee;
    INSERT INTO employee(employee_id, name) VALUES ('1', 'shindo');
    AFTER_TEST_METHOD
    も指定可能

    View full-size slide

  27. トランザクション管理
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 27
    • ロールバックしないと・・・
    DB
    テスト1回目
    INSERT INTO employee
    (employee_id, name)
    VALUES(1, ‘shindo’);
    テスト2回目
    INSERT INTO employee
    (employee_id, name)
    VALUES(1, ‘shindo’);
    employee
    (id=1,
    name=shindo)
    PK重複
    employee
    (id=1,
    name=shindo)

    View full-size slide

  28. @Transactionalでロールバック
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 28
    @DataJpaTest
    public class EmployeeRepositoryTest {
    @Autowired EmployeeRepository repository;
    @Autowired JdbcTemplate jdbcTemplate;
    @Autowired EntityManager entityManager;
    @Test
    @Transactional
    void testSave() {
    Employee employee = new Employee();
    employee.setName("spring");
    employee = repository.save(employee);
    entityManager.flush();
    int count = JdbcTestUtils.countRowsInTable(jdbcTemplate, "employee");
    assertEquals(1, count);
    }
    }
    テストメソッドがトランザクション境界となり、
    メソッドが終わると自動でロールバックされる
    コミットさせたい場合は、@Transactionalの代わりに
    @Commitを使う

    View full-size slide

  29. JPA Repositoryの場合はflush()が必要
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 29
    @DataJpaTest
    public class EmployeeRepositoryTest {
    @Autowired EmployeeRepository repository;
    @Autowired JdbcTemplate jdbcTemplate;
    @Autowired EntityManager entityManager;
    @Test
    @Transactional
    void testSave() {
    Employee employee = new Employee();
    employee.setName("spring");
    employee = repository.save(employee);
    entityManager.flush();
    int count = JdbcTestUtils.countRowsInTable(jdbcTemplate, "employee");
    assertEquals(1, count);
    }
    }
    トランザクション境界の前にflush()して
    SQLを発行させる
    JPAについて詳しくは@suke_masaの
    資料を参照

    View full-size slide

  30. 実行結果の検証
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 30
    1. JdbcTemplateでテーブルをクエリする
    2. JdbcTestUtils
    • テーブル名を指定するだけで行数などを取得できる
    • 行、テーブルの削除も可能
    @Test
    @Transactional
    void testSave() {
    Employee employee = new Employee();
    employee.setName("spring");
    employee = repository.save(employee);
    entityManager.flush();
    // JdbcTemplateを使う場合
    int count = jdbcTemplate.queryForObject("select count(*) from employee", Integer.class);
    assertEquals(1, count);
    // JdbcTestUtilsを使う場合
    count = JdbcTestUtils.countRowsInTable(jdbcTemplate, "employee");
    assertEquals(1, count);
    }

    View full-size slide

  31. DBテストフレームワーク
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 31
    1. DBUnit
    ➢ xml, excelなどでテストデータのセットアップと結果の検証ができる
    ➢ 設定用のコードが多く必要だったり、JUnit 5に追従できていなかったりと不
    便。
    2. Database Rider
    ➢ DBUnitをベースに、アノテーションで楽に設定できるように
    ➢ Springとの連携も容易

    View full-size slide

  32. Spring Webテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 32

    View full-size slide

  33. MockMvcとは
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 33
    1. サーバーにデプロイせずに、Spring MVCのインテグレーションテ
    ストを支援するためのクラス
    2. DispatcherServletに擬似的なリクエストを投げて、パスに対応す
    るHandlerを呼び出す

    View full-size slide

  34. MockMvcの仕組み
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 34
    ① リクエストパスやパラメータなどを設定
    ② 疑似的なリクエストを行う
    ③ リクエスト内容に一致するHandlerを呼び出す
    ④ レスポンス内容の検証を行う
    テストコード MockMvc DispatcherServlet
    Handler
    (Controller)
    Spring MVC
    ① ② ③

    View full-size slide

  35. GETメソッドのテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 35
    @SpringBootTest
    @AutoConfigureMockMvc
    public class HelloControllerTest {
    @Autowired
    MockMvc mockMvc;
    @Test
    void testHello() throws Exception {
    mockMvc.perform(
    MockMvcRequestBuilders.get("/hello").accept(MediaType.TEXT_PLAIN)
    )
    .andExpect(
    MockMvcResultMatchers.status().is2xxSuccessful())
    .andExpect(
    MockMvcResultMatchers.content().string("Hi, Spring Fest 2020"));
    }
    }
    Spring Bootの場合は
    このアノテーションだけで設定可能
    リクエスト内容、検証内容を
    メソッドチェーンで記述する

    View full-size slide

  36. GETメソッドのテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 36
    @SpringBootTest
    @AutoConfigureMockMvc
    public class HelloControllerTest {
    @Autowired
    MockMvc mockMvc;
    @Test
    void testHello() throws Exception {
    mockMvc.perform(
    get("/hello").accept(MediaType.TEXT_PLAIN)
    )
    .andExpect(status().is2xxSuccessful())
    .andExpect(content().string("Hi, Spring Fest 2020"));
    }
    }

    View full-size slide

  37. POSTメソッドのテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 37
    @Autowired
    ObjectMapper objectMapper;
    @Test
    void testCalc() throws Exception {
    CalcRequest request = new CalcRequest();
    request.setLeftSide(2);
    request.setRightSide(3);
    request.setOperator("+");
    mockMvc.perform(
    post("/calc")
    .content(objectMapper.writeValueAsBytes(request))
    .contentType(MediaType.APPLICATION_JSON)
    .accept(MediaType.APPLICATION_JSON)
    )
    .andExpect(status().is2xxSuccessful())
    .andExpect(jsonPath("$.result", CoreMatchers.is(5.0)));
    }
    JSONのリクエストは要シリアライズ
    JSONのフィールドを検証可能

    View full-size slide

  38. デバッグロギング
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 38
    @Test
    void testHello() throws Exception {
    mockMvc.perform(
    get("/hello").accept(MediaType.TEXT_PLAIN)
    )
    .andDo(MockMvcResultHandlers.print())
    (後略)
    (一部)
    MockHttpServletResponse:
    Status = 200
    Error message = null
    Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"20"]
    Content type = text/plain;charset=UTF-8
    Body = Hi, Spring Fest 2020
    Forwarded URL = null
    Redirected URL = null
    Cookies = []
    print()の場合は標準出力
    log()も利用可

    View full-size slide

  39. Web API アクセスのモック化
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 39
    Web API
    Springアプリケーション
    HTTP
    モック
    テストのときはHTTPコールを
    モック化したい

    View full-size slide

  40. MockRequestServiceServer
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 40
    1. RestTemplateのふるまいをモック化するクラス
    2. RestTemplateの内部のClientHttpRequestFactoryをモックに差
    し替えることで、RestTemplateを使っているコードを変更するこ
    となく、HTTPコールをモック化できる
    RestTemplate

    ClientHttpRequest
    Factory
    HttpComponentsClient
    HttpRequestFactory
    MockClientHttp
    RequestFactory

    View full-size slide

  41. MockRequestServiceServer
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 41
    @SpringBootTest
    class WeatherForecastApiRepositoryTest {
    @Autowired
    WeatherForecastApiRepository repository;
    @Autowired
    RestTemplate restTemplate;
    @Test
    void retrieveForecastAt() {
    MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
    server.expect(MockRestRequestMatchers.method(HttpMethod.GET))
    .andExpect(requestTo("http://foo.domain/forecast?location=Tokyo"))
    .andRespond(MockRestResponseCreators.withSuccess()
    .contentType(MediaType.APPLICATION_JSON)
    .body("{¥"location¥":¥"Tokyo¥",¥"weather¥":¥"sunny¥"}"));
    Forecast actual = repository.retrieveForecastAt("Tokyo");
    assertEquals("Tokyo", actual.getLocation());
    assertEquals("sunny", actual.getWeather());
    }
    }
    RestTemplateはテスト対象のBeanを取得
    RestTemplateの中身をモックに差し替え
    モックのふるまいを設定する

    View full-size slide

  42. Spring Bootテスト
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 42

    View full-size slide

  43. @SpringBootTest
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 43
    1. Spring Bootアプリケーションをテストするためのアノテーション
    2. @SpringBootApplicationを検知して各種設定を自動的にロード
    3. 組み込みサーブレットコンテナを実際に立ち上げて、
    本物のHTTPリクエスト/レスポンスを投げてテストができる

    View full-size slide

  44. Copyright © Acroquest Technology Co., Ltd. All rights reserved. 44
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class ApiTest {
    @LocalServerPort
    int port;
    @Test
    void testHello() {
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:" + port + "/hello";
    ResponseEntity entity = restTemplate.getForEntity(url, String.class);
    assertEquals(HttpStatus.OK, entity.getStatusCode());
    assertEquals("Hi, Spring Fest 2020", entity.getBody());
    }
    }
    ランダムなポートでサーバーを起動
    サーバーポートを取得
    RestTemplateを使って
    本物のHTTPリクエストを実行

    View full-size slide

  45. WebEnvironment
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 45
    • @SpringBootTestで指定できるWebEnvironmentは下記の通り
    No WebEnvironment
    1 MOCK
    (デフォルト)
    モックサーブレット環境を構成する。(実際のポートはリッスンしな
    い)
    @AutoConfigureMockMvcを組み合わせる。
    2 RANDOM_PORT 組み込みサーブレットコンテナを起動し、ランダムなポートをリッス
    ンする。
    3 DEFINED_PORT 組み込みサーブレットコンテナを起動し、プロパティで定義されたポ
    ートをリッスンする。
    4 NONE ApplicationContextをロードするが、サーブレット環境を構成しな
    い。
    バッチなどの非Webアプリケーションで利用する。

    View full-size slide

  46. MockMvcとの違い
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 46
    RANDOM_PORT/
    DEFINED_PORT
    MockMvc
    実行環境
    組み込みサーブレットコンテナ
    を実際に起動
    モックサーブレット
    起動時間
    実環境と同一なため
    低速
    モック環境のため
    (比較的)高速
    トランザクション ロールバック不可 @Transactionalで
    ロールバック可能
    テストメソッドとは別のスレッドで処理が
    実行されるため、テストコードから
    トランザクション管理できない

    View full-size slide

  47. TestRestTemplate
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 47
    1. インテグレーションテスト用のRestTemplate
    2. webEnvironment=RANDOM_PORT/DEFINED_PORT
    の場合に、サーバーポートが自動的に設定される
    3. デフォルトでクッキーとリダイレクトが無効化されている

    View full-size slide

  48. TestRestTemplate
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 48
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class ApiTest {
    @Autowired
    TestRestTemplate restTemplate;
    @Test
    void testHello() {
    ResponseEntity entity = restTemplate.getForEntity("/hello", String.class);
    assertEquals(HttpStatus.OK, entity.getStatusCode());
    assertEquals("Hi, Spring Fest 2020", entity.getBody());
    }
    }
    @LocalServerPort不要

    View full-size slide

  49. WebTestClient
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 49
    1. インテグレーションテスト用のWebClient
    2. TestRestTemplateと同様、サーバーポートが自動的に
    設定される
    3. レスポンスの検証を流れるようなインターフェースで記述できる
    4. 要spring-boot-starter-webflux

    View full-size slide

  50. WebTestClient
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 50
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class ApiTest {
    @Autowired
    WebTestClient client;
    @Test
    void testHello() {
    client.get().uri("/hello")
    .exchange()
    .expectStatus().isOk()
    .expectBody(String.class).isEqualTo("Hi, Spring Fest 2020");
    }
    }

    View full-size slide

  51. その他小ネタ
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 51

    View full-size slide

  52. MockMvcWebTestClient
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 52
    @ExtendWith(SpringExtension.class)
    @WebMvcTest(controllers = HelloController.class)
    public class WebTestClientTest {
    @Autowired
    WebApplicationContext wac;
    WebTestClient client;
    @BeforeEach
    void setup() {
    client = MockMvcWebTestClient.bindToApplicationContext(wac).build();
    }
    @Test
    void testWebTestClient() {
    client.get()
    .uri("/hello")
    .exchange()
    .expectStatus().isOk()
    .expectBody(String.class).isEqualTo("Hi, Spring Fest 2020");
    }
    }
    詳しくは@makingの
    『What's New in Spring 5.3 and Spring Boot 2.4』
    をチェック!

    View full-size slide

  53. アノテーションが多すぎる問題
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 53
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @SqlGroup({
    @Sql(scripts = "classpath:/employee.sql",
    executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD),
    @Sql(scripts = "classpath:/truncate.sql",
    executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
    })
    public class ApiTest {
    アノテーション多すぎ
    同じレイヤーのテストに対しては、
    大体同じアノテーションをつけることになる

    View full-size slide

  54. 合成アノテーションで解決
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 54
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @SqlGroup({
    @Sql(scripts = "classpath:/employee.sql",
    executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD),
    @Sql(scripts = "classpath:/truncate.sql",
    executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
    })
    public @interface ApiTestSupport {
    }
    @ApiTestSupport
    public class ApiTest {
    合成アノテーションを作成して共通化する

    View full-size slide

  55. Furthermore…
    Copyright © Acroquest Technology Co., Ltd. All rights reserved. 55
    • WebFlux Test
    • spring-security-test
    • mybatis-spring-boot-starter-test
    • Testcontainers

    View full-size slide