Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
今こそ知りたいSpring Test / Spring Fest 2020
Search
Ryo Shindo
December 17, 2020
Programming
11
5.8k
今こそ知りたいSpring Test / Spring Fest 2020
Spring Fest 2020 Beginner Track
https://springfest2020.springframework.jp/
Ryo Shindo
December 17, 2020
Tweet
Share
More Decks by Ryo Shindo
See All by Ryo Shindo
こわくないソースコードリーディング生活 / JJUG CCC 2019 Fall
rshindo
15
9.2k
開発者のためのSpring Boot Actuator入門 / jsug-2019-08
rshindo
5
5.7k
早わかりSpring Data JDBC / jsug-2019-01
rshindo
5
4.1k
ふつうのJavaアプリ開発のための自動テスト戦略 / JJUG CCC 2018 Fall
rshindo
9
4.9k
Spring WebFluxで学ぶReactive Application / Introduction to Reactive
rshindo
1
2.2k
まだまだ間に合う!JUnit 5入門 / JJUG CCC 2018 Spring
rshindo
6
3.2k
Spring Data JDBCを使い倒す! / Intruduction to Spring Data JDBC
rshindo
4
2.2k
Other Decks in Programming
See All in Programming
Mermaid x AST x 生成AI = コードとドキュメントの完全同期への道
shibuyamizuho
0
160
今からはじめるAndroidアプリ開発 2024 / DevFest 2024
star_zero
0
1k
rails statsで大解剖 🔍 “B/43流” のRailsの育て方を歴史とともに振り返ります
shoheimitani
2
930
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
あれやってみてー駆動から成長を加速させる / areyattemite-driven
nashiusagi
1
200
Symfony Mapper Component
soyuka
2
730
The Efficiency Paradox and How to Save Yourself and the World
hollycummins
1
440
KubeCon + CloudNativeCon NA 2024 Overviewat Kubernetes Meetup Tokyo #68 / amsy810_k8sjp68
masayaaoyama
0
250
.NET 9アプリをCGIとして レンタルサーバーで動かす
mayuki
1
770
fs2-io を試してたらバグを見つけて直した話
chencmd
0
220
Keeping it Ruby: Why Your Product Needs a Ruby SDK - RubyWorld 2024
envek
0
180
Stackless и stackful? Корутины и асинхронность в Go
lamodatech
0
690
Featured
See All Featured
Building Adaptive Systems
keathley
38
2.3k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
665
120k
A better future with KSS
kneath
238
17k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
232
17k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
Building Your Own Lightsaber
phodgson
103
6.1k
A Tale of Four Properties
chriscoyier
157
23k
Reflections from 52 weeks, 52 projects
jeffersonlam
347
20k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
Mobile First: as difficult as doing things right
swwweet
222
9k
Code Reviewing Like a Champion
maltzj
520
39k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
247
1.3M
Transcript
1 Copyright © Acroquest Technology Co., Ltd. All rights reserved.
今こそ知りたいSpring Test Spring Fest 2020 Acroquest Technology株式会社 進藤 遼(@shindo_ryo)
自己紹介 • 進藤 遼 • Acroquest Technology株式会社 • 日本Springユーザ会 スタッフ
• Twitter: @shindo_ryo • 好きなSpring Projectは Spring Cloud Sleuth Copyright © Acroquest Technology Co., Ltd. All rights reserved. 2
目次 Copyright © Acroquest Technology Co., Ltd. All rights reserved.
3 1. Spring Testの基礎 2. モックテスト 3. DBテスト 4. Spring Webテスト 5. Spring Bootテスト 6. その他
Spring Testの基礎 Copyright © Acroquest Technology Co., Ltd. All rights
reserved. 4
Spring Testとは Copyright © Acroquest Technology Co., Ltd. All rights
reserved. 5 1. Springアプリケーションに対するインテグレーションテストを サポートするモジュール 2. JUnit, TestNGといったテスティングフレームワークと連携する ※デフォルトでJUnit 5 3. Spring MVCのテスト、DBテストなどを容易にする ユーティリティを多数提供
Spring Testのインストール Copyright © Acroquest Technology Co., Ltd. All rights
reserved. 6 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> デフォルトで設定済み
SpringのDIの仕組み Copyright © Acroquest Technology Co., Ltd. All rights reserved.
7 DIコンテナ (ApplicationContext) Bean Bean 使う new new 依存オブジェクトを注入
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コンテナが依存オブジェクトを注入
通常のユニットテスト 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()); } }
Spring Testを使わないと・・・ Copyright © Acroquest Technology Co., Ltd. All rights
reserved. 10 1. 全てのインスタンスを自前でnew ➢ controller層からrepository層まで統合しようとすると 非常に多くのBeanが必要になる 2. 正しくDIできることをテストできない ➢ Beanが不足、または重複していても気づけない
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を取得
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~)
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は キャッシュされて使い回される
テスト実行フロー Copyright © Acroquest Technology Co., Ltd. All rights reserved.
14 テストクラスのロード ApplicationContextの初期化 テストクラスにSpring Beanを注入 各テストメソッドを実行 SpringExtension @Test JUnit
スライステスト 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
モックテスト Copyright © Acroquest Technology Co., Ltd. All rights reserved.
16
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
@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化された振る舞いを指定
@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で注入する
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が異なる
@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とは 別のもの扱いとなる
モックテストでも遅くならないようにする方法 Copyright © Acroquest Technology Co., Ltd. All rights reserved.
22 1. 各テストクラスでモック対象のクラスを完全に同一にする • 共通のJava Configを作って@ContextConfigurationで指定 • 一つでも違う部分があるとアウト 2. @MockBean/@SpyBeanを使わない • モックを使うテストではSpring Testを使わない • モッククラスを自作して、テスト中は@Primaryで差し替え @Service @Primary public class MockBarService { }
DBテスト Copyright © Acroquest Technology Co., Ltd. All rights reserved.
23
DBテストのフロー Copyright © Acroquest Technology Co., Ltd. All rights reserved.
24 テストデータのセットアップ テストの実行 更新後のデータの検証 ロールバック / テストデータの破棄 テストデータの状態を一定に保つことで テストのべき等性を担保する
テストデータのセットアップの2つの方法 Copyright © Acroquest Technology Co., Ltd. All rights reserved.
25 ① schema.sql / data.sql をクラスパスに配置する • DataSourceの初期化の段階で自動的に実行される • テストクラスごと、テストメソッドごとのような実行サイクルはできない ② テストクラス、テストメソッドに@Sqlを指定する • 任意のSQLファイルを読み込み実行する • テストメソッドの前後で実行させることができる
@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 も指定可能
トランザクション管理 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)
@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を使う
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の 資料を参照
実行結果の検証 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); }
DBテストフレームワーク Copyright © Acroquest Technology Co., Ltd. All rights reserved.
31 1. DBUnit ➢ xml, excelなどでテストデータのセットアップと結果の検証ができる ➢ 設定用のコードが多く必要だったり、JUnit 5に追従できていなかったりと不 便。 2. Database Rider ➢ DBUnitをベースに、アノテーションで楽に設定できるように ➢ Springとの連携も容易
Spring Webテスト Copyright © Acroquest Technology Co., Ltd. All rights
reserved. 32
MockMvcとは Copyright © Acroquest Technology Co., Ltd. All rights reserved.
33 1. サーバーにデプロイせずに、Spring MVCのインテグレーションテ ストを支援するためのクラス 2. DispatcherServletに擬似的なリクエストを投げて、パスに対応す るHandlerを呼び出す
MockMvcの仕組み Copyright © Acroquest Technology Co., Ltd. All rights reserved.
34 ① リクエストパスやパラメータなどを設定 ② 疑似的なリクエストを行う ③ リクエスト内容に一致するHandlerを呼び出す ④ レスポンス内容の検証を行う テストコード MockMvc DispatcherServlet Handler (Controller) Spring MVC ① ② ③ ④
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の場合は このアノテーションだけで設定可能 リクエスト内容、検証内容を メソッドチェーンで記述する
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")); } }
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のフィールドを検証可能
デバッグロギング 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()も利用可
Web API アクセスのモック化 Copyright © Acroquest Technology Co., Ltd. All
rights reserved. 39 Web API Springアプリケーション HTTP モック テストのときはHTTPコールを モック化したい
MockRequestServiceServer Copyright © Acroquest Technology Co., Ltd. All rights reserved.
40 1. RestTemplateのふるまいをモック化するクラス 2. RestTemplateの内部のClientHttpRequestFactoryをモックに差 し替えることで、RestTemplateを使っているコードを変更するこ となく、HTTPコールをモック化できる RestTemplate <interface> ClientHttpRequest Factory HttpComponentsClient HttpRequestFactory MockClientHttp RequestFactory
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の中身をモックに差し替え モックのふるまいを設定する
Spring Bootテスト Copyright © Acroquest Technology Co., Ltd. All rights
reserved. 42
@SpringBootTest Copyright © Acroquest Technology Co., Ltd. All rights reserved.
43 1. Spring Bootアプリケーションをテストするためのアノテーション 2. @SpringBootApplicationを検知して各種設定を自動的にロード 3. 組み込みサーブレットコンテナを実際に立ち上げて、 本物のHTTPリクエスト/レスポンスを投げてテストができる
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<String> entity = restTemplate.getForEntity(url, String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); assertEquals("Hi, Spring Fest 2020", entity.getBody()); } } ランダムなポートでサーバーを起動 サーバーポートを取得 RestTemplateを使って 本物のHTTPリクエストを実行
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アプリケーションで利用する。
MockMvcとの違い Copyright © Acroquest Technology Co., Ltd. All rights reserved.
46 RANDOM_PORT/ DEFINED_PORT MockMvc 実行環境 組み込みサーブレットコンテナ を実際に起動 モックサーブレット 起動時間 実環境と同一なため 低速 モック環境のため (比較的)高速 トランザクション ロールバック不可 @Transactionalで ロールバック可能 テストメソッドとは別のスレッドで処理が 実行されるため、テストコードから トランザクション管理できない
TestRestTemplate Copyright © Acroquest Technology Co., Ltd. All rights reserved.
47 1. インテグレーションテスト用のRestTemplate 2. webEnvironment=RANDOM_PORT/DEFINED_PORT の場合に、サーバーポートが自動的に設定される 3. デフォルトでクッキーとリダイレクトが無効化されている
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<String> entity = restTemplate.getForEntity("/hello", String.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); assertEquals("Hi, Spring Fest 2020", entity.getBody()); } } @LocalServerPort不要
WebTestClient Copyright © Acroquest Technology Co., Ltd. All rights reserved.
49 1. インテグレーションテスト用のWebClient 2. TestRestTemplateと同様、サーバーポートが自動的に 設定される 3. レスポンスの検証を流れるようなインターフェースで記述できる 4. 要spring-boot-starter-webflux
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"); } }
その他小ネタ Copyright © Acroquest Technology Co., Ltd. All rights reserved.
51
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』 をチェック!
アノテーションが多すぎる問題 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 { アノテーション多すぎ 同じレイヤーのテストに対しては、 大体同じアノテーションをつけることになる
合成アノテーションで解決 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 { 合成アノテーションを作成して共通化する
Furthermore… Copyright © Acroquest Technology Co., Ltd. All rights reserved.
55 • WebFlux Test • spring-security-test • mybatis-spring-boot-starter-test • Testcontainers