SpringBoot/テスト
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
]
開始行:
[[SpringBoot]]
- 4/5中田
* Spring Boot Test [#i322aa14]
Spring Bootでのテストの仕方をまとめ%%たかった%%
#contents
** はじめに [#ad97d481]
公式Docを読む時間がある人は[[この項目:https://docs.spring...
テストについて学ぶには、Spring Framework、Spring Bootにつ...
PitCoinで実際にテストを書いてみたので、[[こちら:http://te...
** Spring Bootテスト全体の話 [#yb02716f]
*** テストで使用する技術 [#me700c2d]
Spring Bootでテストを行うためには、様々な知識が必要です。
Spring Frameworkのテスト = (バニラJava + 頻出ライブラリ)...
- バニラJava
-- 標準のJavaの書き方です。
-- (例:OOP、アノテーション、ラムダ式、JPA)
- 頻出ライブラリ
-- Javaでよく使われるライブラリです。
-- (例:Jackson)
- テスト
-- テストの本体です。
-- (例:JUnit5、JUnit4)
- アサーション
-- テストで満たすべき条件を記述します。
-- (例:AssertJ)
- DI
-- Bean注入です。
-- (例:@Bean、@Autowired、コンポーネントスキャン)
- モッキング
-- 注入するBeanをモック(はりぼてクラス)にすることで、クラ...
-- (例:Mockito)
- Auto-configuration
-- Springの主機能で、依存性を記述するだけで指定した範囲の...
*** Bootテストの特徴 [#kc0bd9fb]
Spring Bootのテストは、Spring Frameworkのテストをまとめた...
build.gradleに testImplementation 'org.springframework.bo...
- JUnit 5 : テストライブラリ
- AssertJ : アサーションライブラリ
- Mockito : モッキングフレームワーク
テストの種類に応じてアノテーションを変更することで、コン...
Auto-configurationの内容は、[[@SpringBootTest:https://doc...
@...Testのアノテーションは、 JUnit5の@ExtendWith(SpringEx...
** 具体的なテスト手法 [#yb49ccc2]
*** Repository単体テスト(Spring Data JPA) [#y6b75efb]
[[公式Doc:https://docs.spring.io/spring-boot/docs/2.4.3/r...
//公式Docより
@DataJpaTest
class ExampleRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() throws Exception {
this.entityManager.persist(new User("sboot", "12...
User user = this.repository.findByUsername("sboo...
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("1234");
}
}
Repository単体テストでは、インメモリのDBを利用します。
そのため、テスト用に依存を追加しておく必要があります。(例...
@DataJpaTestは、@RepositoryをスキャンしてBeanを自動構成す...
また、TestEntityManager(標準JavaのJPAにおけるEntityManage...
@DataJpaTestは@Transactionalを含むアノテーションであるた...
*** Repository+DBの結合テスト [#f06172db]
インメモリではなく、設定ファイルで定義したDBに対してテス...
// 公式Docより
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
class ExampleRepositoryTests {
// ...
}
この時利用するデータベース設定は、application.propetiesか...
src/test/resources -> src/main/resources の順で走査され、...
本番・開発用のDBを汚染しないように、テスト用データベース...
*** Serviceの単体テスト [#vddb80ad]
// 静的インポート(他のインポートは省略)
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
// モックを有効化
@ExtendWith(MockitoExtension.class)
public class MyServiceUnitTests {
// Repositoryをモックに
@Mock
private MyRepository repository;
// モックRepositoryを注入してServiceを構成
@InjectMocks
private MyService service;
@Test
void testMethod(){
// Serviceで呼び出されるRepositoryメソッドの動作を定義
given(repository.myRepositoryMethod(a)).willReturn(b);
// Serviceを呼び出す(内部で上で定義した動作が動く)
final returnValue = service.myServiceMethod(a);
// 適当なアサーションを行う
asertThat(returnValue.getName()).isEqualTo(b);
}
}
Service単体テストでは、テスト対象のService内で使用する他...
上の例では、@ExtendWith(MockitoExtension.class)でモックBe...
テストメソッドの中では、
- given().willReturn()の構文でモックメソッドの動作を定義...
- テスト対象のServiceメソッドを動かし、
- アサーション
という手順でテストを行っています。
また、今回はAuto-configurationの必要がなく(モック以外で特...
必要な機能を付加したい場合は@AutoConfigure...を、自作クラ...
もしくは、@...Testを利用してもよいですが、その場合はアノ...
*** Service+Repository+DB結合テスト[#h6a24d85]
// 静的インポート(他のインポートは省略)
import static org.assertj.core.api.Assertions.*;
// クラスアノテーションの説明は下記
/*
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvir...
@AutoConfigureTestEntityManager
@Transactional
*/
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDa...
@Import(MyService.class)
public class MyServiceIntegrationTests {
// モックではなく全てAutowired
@Autowired
private TestEntityManager entityManager;
@Autowired
private MyRepository repository;
@Autowired
private MyService service;
@Test
void testMethod(){
// テスト内容
}
}
Serviceクラス以下の結合テストです。上の例では特にモックは...
テストの手順の一例は次の通りです。
- TestEntityManagerでDBを初期化
- テスト対象のServiceを動かす
- 戻り値等をアサーション
- DBの中身をRepositoryで取得してアサーション
**** 結合テストクラスアノテーション [#qd3a2eb4]
結合テストのアノテーションは、テストの方針によって付加の...
この話はService+Repository+DBに限らず、部分的な結合テスト...
一つ目は、ほぼ全体をスキャンしてから必要に応じて機能を付...
- @SpringBootTest(webEnvironment = SpringBootTest.WebEnvi...
-- 基本のコンポーネントスキャンを全て行う
-- 基本のAuto-configurationを全て行う(一部行わない)
-- Webサーバーを非起動にする(サーバーに関しては後述)
- @AutoConfigureTestEntityManager
-- TestEntityManagerのBeanを生成する
- @Transactional
-- テストごとにトランザクションをロールバックする
結合の規模が大きい場合は便利ですが、機能の制限が面倒であ...
二つ目は、最大公約数的な@...Testを付加してから必要に応じ...
- @DataJpaTest
-- Repositoryをスキャンする
-- DataJpaまわりのAuto-configurationを行う
-- テストごとにトランザクションをロールバックする
-- TestEntityManagerのBeanを生成する
-- インメモリDBを利用する(下で打ち消し)
- @AutoConfigureTestDatabase(replace = AutoConfigureTestD...
-- インメモリDBを利用しない(上の最後の項目の打ち消し)
- @Import(MyService.class)
-- 必要なServiceをスキャンする
結合の規模が小さい場合や必要な機能が少ない場合は便利です...
*** Controller単体テスト(MVCテスト) [#f9290307]
[[公式Doc:https://docs.spring.io/spring-boot/docs/2.4.3/r...
// 静的インポート
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.reque...
import static org.springframework.test.web.servlet.resul...
// MockMvcの有効化など
@WebMvcTest(MyController.class)
public class MyControllerUnitTests {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper mapper;
// Spring Boot版モック生成
@MockBean
private MyService service;
@Test
void testMethod() throws Exception { // MockMvcはExce...
// モックメソッド定義
given(service.myMethod(a)).willReturn(b);
// REST呼び出しとアサーションを同時に行う
mvc
.perform(post("/this/is/path/")
.content(mapper.writeValueAsStrin...
.contentType(MediaType.APPLICATIO...
.andExpect(status().isOk())
.andExpect(jsonPath("$.result.name").value(b));
}
}
Controller単体テストでは、MockMvcを用いることでサーバーを...
@WebMvcTest(...)によって、以下が行われます。
- @Controller(つまり@RestControllerも含む)、@ControllerAd...
- MockMvcのBean生成
- JacksonのObjectMapperのBean生成
- @MockBeanが使用可能
- Spring Securityの有効化(依存関係があれば)
- SpringのValidationの有効化(依存関係があれば)
また、引数として渡した単一のControllerに対して、モックBea...
@MockBeanはSpring Boot版のモック生成アノテーションで、@We...
上の例では、Controller内で呼び出すServiceをモックにしてい...
MockMvcは、performでAPIを疑似的に叩き、andExpectで戻り値...
例では、引数としてJSONをボディに持つPOSTを叩き、戻り値の...
詳細やGET等の他の方法はここでは省略します。
Spring Securityのテストをしたい方は、自分は当分使う機会が...
Thymeleafも検証可能です
.andExpect(view().name("hoge"))
.andExpect(model().attribute("name", name));
*** 全体(Controller+Service+Repository+DB)結合テスト [#p1...
// 静的インポート
import static org.assertj.core.api.Assertions.*;
import static org.springframework.test.web.servlet.reque...
import static org.springframework.test.web.servlet.resul...
// もろもろのクラスアノテーション
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureTestEntityManager
@Transactional
public class PitCoinUserControllerIntegrationTests {
// モックなし
@Autowired
private MockMvc mvc;
@Autowired
private TestEntityManager entityManager;
@Autowired
private ObjectMapper mapper;
@Autowired
private AccountRepository accounts;
@Test
void testMethod() throws Exception{
// テスト内容
}
}
はじめに注意として、これは"全体"結合テストですが、サーバ...
その理由は以下の通りです。
- サーバーを起動しなくともテスト結果に影響が出なさそうだ...
- サーバーを起動するとMockMvcが使えなくなり、記法を変更す...
-- MockMvcの代替1 : TestWebClient
--- 利点 : サーバーの起動・非起動に関わらず使用可能
--- 欠点 : WebFluxとかいう未知技術, RepositoryがFlux対応...
-- MockMvcの代替2 : TestRestTemplate
--- 利点 : RestTemplateと同様に使える
--- 欠点 : ''将来的にRestTemplateともども廃止予定''
全体結合テストの手順の例は以下の通りです。
- TestEntityManagerでDBを初期化する。
- MockMvcで疑似REST呼び出しを行い、アサーションを行う
- DBの中身をRepositoryで呼び出し、アサーションを行う
** テストで使用するライブラリの簡単な使い方 [#cd810d25]
*** JUnit5 [#w8214240]
// テストメソッド
@Test
void testMethod(){
// テスト内容
}
// 各テスト前に実行するメソッド
@BeforeEach
void beforeEach(){
// DBの初期化等
}
class AllTests{
// 入れ子クラスをテスト対象にする
@Nested
class HalfTests{
@Test
void testMethod(){
// テスト内容
}
}
}
// テストクラスで様々な拡張機能を使用可能にする
@ExtendWith(...Extension.class)
public class TestClass {
// テスト
}
*** AssertJ [#i285d123]
// アサーションメソッドを静的インポートする
import static org.assertj.core.api.Assertions.*;
// aとbが一致するかチェック
assertThat(a).isEqualTo(b);
// 真偽値をチェック
assertThat(a).isTrue();
assertThat(b).isFalse();
// 例外チェック
assertThatThrownBy(() -> {
// 例外が発生する処理
}).
isInstanceOfSatisfying(
/* 正しい例外クラス */,
(e) ->{
// 発生した例外eが満たすべき条件のアサーションを記...
}
);
*** Mockito(BDD) [#k763d9ab]
// BDDMockメソッドの静的インポート
import static org.mockito.BDDMockito.*;
//JUnit5でモックの作成・注入を可能にする
@ExtendWith(MockitoExtension.class)
public class TestClass{
// モックを使ったテスト
}
// モック
@Mock
private SubService sub;
// 内部でモックを利用する(=モックを注入される)
@InjectMocks
private Service service;
// 注入先での動作を定義する
// service.myMethod(a)が呼ばれるとbを返す
given(service.myMethod(a)).willReturn(b);
// service.myMethod()の引数にMyClass型が渡されるとcを返す
given(service.myMethod(any(MyClass.class))).willReturn(c);
** 今後の積み残し [#m1c4c104]
- 外部API呼び出しのモック
- サービス間連携でのテスト
終了行:
[[SpringBoot]]
- 4/5中田
* Spring Boot Test [#i322aa14]
Spring Bootでのテストの仕方をまとめ%%たかった%%
#contents
** はじめに [#ad97d481]
公式Docを読む時間がある人は[[この項目:https://docs.spring...
テストについて学ぶには、Spring Framework、Spring Bootにつ...
PitCoinで実際にテストを書いてみたので、[[こちら:http://te...
** Spring Bootテスト全体の話 [#yb02716f]
*** テストで使用する技術 [#me700c2d]
Spring Bootでテストを行うためには、様々な知識が必要です。
Spring Frameworkのテスト = (バニラJava + 頻出ライブラリ)...
- バニラJava
-- 標準のJavaの書き方です。
-- (例:OOP、アノテーション、ラムダ式、JPA)
- 頻出ライブラリ
-- Javaでよく使われるライブラリです。
-- (例:Jackson)
- テスト
-- テストの本体です。
-- (例:JUnit5、JUnit4)
- アサーション
-- テストで満たすべき条件を記述します。
-- (例:AssertJ)
- DI
-- Bean注入です。
-- (例:@Bean、@Autowired、コンポーネントスキャン)
- モッキング
-- 注入するBeanをモック(はりぼてクラス)にすることで、クラ...
-- (例:Mockito)
- Auto-configuration
-- Springの主機能で、依存性を記述するだけで指定した範囲の...
*** Bootテストの特徴 [#kc0bd9fb]
Spring Bootのテストは、Spring Frameworkのテストをまとめた...
build.gradleに testImplementation 'org.springframework.bo...
- JUnit 5 : テストライブラリ
- AssertJ : アサーションライブラリ
- Mockito : モッキングフレームワーク
テストの種類に応じてアノテーションを変更することで、コン...
Auto-configurationの内容は、[[@SpringBootTest:https://doc...
@...Testのアノテーションは、 JUnit5の@ExtendWith(SpringEx...
** 具体的なテスト手法 [#yb49ccc2]
*** Repository単体テスト(Spring Data JPA) [#y6b75efb]
[[公式Doc:https://docs.spring.io/spring-boot/docs/2.4.3/r...
//公式Docより
@DataJpaTest
class ExampleRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() throws Exception {
this.entityManager.persist(new User("sboot", "12...
User user = this.repository.findByUsername("sboo...
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("1234");
}
}
Repository単体テストでは、インメモリのDBを利用します。
そのため、テスト用に依存を追加しておく必要があります。(例...
@DataJpaTestは、@RepositoryをスキャンしてBeanを自動構成す...
また、TestEntityManager(標準JavaのJPAにおけるEntityManage...
@DataJpaTestは@Transactionalを含むアノテーションであるた...
*** Repository+DBの結合テスト [#f06172db]
インメモリではなく、設定ファイルで定義したDBに対してテス...
// 公式Docより
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
class ExampleRepositoryTests {
// ...
}
この時利用するデータベース設定は、application.propetiesか...
src/test/resources -> src/main/resources の順で走査され、...
本番・開発用のDBを汚染しないように、テスト用データベース...
*** Serviceの単体テスト [#vddb80ad]
// 静的インポート(他のインポートは省略)
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
// モックを有効化
@ExtendWith(MockitoExtension.class)
public class MyServiceUnitTests {
// Repositoryをモックに
@Mock
private MyRepository repository;
// モックRepositoryを注入してServiceを構成
@InjectMocks
private MyService service;
@Test
void testMethod(){
// Serviceで呼び出されるRepositoryメソッドの動作を定義
given(repository.myRepositoryMethod(a)).willReturn(b);
// Serviceを呼び出す(内部で上で定義した動作が動く)
final returnValue = service.myServiceMethod(a);
// 適当なアサーションを行う
asertThat(returnValue.getName()).isEqualTo(b);
}
}
Service単体テストでは、テスト対象のService内で使用する他...
上の例では、@ExtendWith(MockitoExtension.class)でモックBe...
テストメソッドの中では、
- given().willReturn()の構文でモックメソッドの動作を定義...
- テスト対象のServiceメソッドを動かし、
- アサーション
という手順でテストを行っています。
また、今回はAuto-configurationの必要がなく(モック以外で特...
必要な機能を付加したい場合は@AutoConfigure...を、自作クラ...
もしくは、@...Testを利用してもよいですが、その場合はアノ...
*** Service+Repository+DB結合テスト[#h6a24d85]
// 静的インポート(他のインポートは省略)
import static org.assertj.core.api.Assertions.*;
// クラスアノテーションの説明は下記
/*
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvir...
@AutoConfigureTestEntityManager
@Transactional
*/
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDa...
@Import(MyService.class)
public class MyServiceIntegrationTests {
// モックではなく全てAutowired
@Autowired
private TestEntityManager entityManager;
@Autowired
private MyRepository repository;
@Autowired
private MyService service;
@Test
void testMethod(){
// テスト内容
}
}
Serviceクラス以下の結合テストです。上の例では特にモックは...
テストの手順の一例は次の通りです。
- TestEntityManagerでDBを初期化
- テスト対象のServiceを動かす
- 戻り値等をアサーション
- DBの中身をRepositoryで取得してアサーション
**** 結合テストクラスアノテーション [#qd3a2eb4]
結合テストのアノテーションは、テストの方針によって付加の...
この話はService+Repository+DBに限らず、部分的な結合テスト...
一つ目は、ほぼ全体をスキャンしてから必要に応じて機能を付...
- @SpringBootTest(webEnvironment = SpringBootTest.WebEnvi...
-- 基本のコンポーネントスキャンを全て行う
-- 基本のAuto-configurationを全て行う(一部行わない)
-- Webサーバーを非起動にする(サーバーに関しては後述)
- @AutoConfigureTestEntityManager
-- TestEntityManagerのBeanを生成する
- @Transactional
-- テストごとにトランザクションをロールバックする
結合の規模が大きい場合は便利ですが、機能の制限が面倒であ...
二つ目は、最大公約数的な@...Testを付加してから必要に応じ...
- @DataJpaTest
-- Repositoryをスキャンする
-- DataJpaまわりのAuto-configurationを行う
-- テストごとにトランザクションをロールバックする
-- TestEntityManagerのBeanを生成する
-- インメモリDBを利用する(下で打ち消し)
- @AutoConfigureTestDatabase(replace = AutoConfigureTestD...
-- インメモリDBを利用しない(上の最後の項目の打ち消し)
- @Import(MyService.class)
-- 必要なServiceをスキャンする
結合の規模が小さい場合や必要な機能が少ない場合は便利です...
*** Controller単体テスト(MVCテスト) [#f9290307]
[[公式Doc:https://docs.spring.io/spring-boot/docs/2.4.3/r...
// 静的インポート
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.reque...
import static org.springframework.test.web.servlet.resul...
// MockMvcの有効化など
@WebMvcTest(MyController.class)
public class MyControllerUnitTests {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper mapper;
// Spring Boot版モック生成
@MockBean
private MyService service;
@Test
void testMethod() throws Exception { // MockMvcはExce...
// モックメソッド定義
given(service.myMethod(a)).willReturn(b);
// REST呼び出しとアサーションを同時に行う
mvc
.perform(post("/this/is/path/")
.content(mapper.writeValueAsStrin...
.contentType(MediaType.APPLICATIO...
.andExpect(status().isOk())
.andExpect(jsonPath("$.result.name").value(b));
}
}
Controller単体テストでは、MockMvcを用いることでサーバーを...
@WebMvcTest(...)によって、以下が行われます。
- @Controller(つまり@RestControllerも含む)、@ControllerAd...
- MockMvcのBean生成
- JacksonのObjectMapperのBean生成
- @MockBeanが使用可能
- Spring Securityの有効化(依存関係があれば)
- SpringのValidationの有効化(依存関係があれば)
また、引数として渡した単一のControllerに対して、モックBea...
@MockBeanはSpring Boot版のモック生成アノテーションで、@We...
上の例では、Controller内で呼び出すServiceをモックにしてい...
MockMvcは、performでAPIを疑似的に叩き、andExpectで戻り値...
例では、引数としてJSONをボディに持つPOSTを叩き、戻り値の...
詳細やGET等の他の方法はここでは省略します。
Spring Securityのテストをしたい方は、自分は当分使う機会が...
Thymeleafも検証可能です
.andExpect(view().name("hoge"))
.andExpect(model().attribute("name", name));
*** 全体(Controller+Service+Repository+DB)結合テスト [#p1...
// 静的インポート
import static org.assertj.core.api.Assertions.*;
import static org.springframework.test.web.servlet.reque...
import static org.springframework.test.web.servlet.resul...
// もろもろのクラスアノテーション
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureTestEntityManager
@Transactional
public class PitCoinUserControllerIntegrationTests {
// モックなし
@Autowired
private MockMvc mvc;
@Autowired
private TestEntityManager entityManager;
@Autowired
private ObjectMapper mapper;
@Autowired
private AccountRepository accounts;
@Test
void testMethod() throws Exception{
// テスト内容
}
}
はじめに注意として、これは"全体"結合テストですが、サーバ...
その理由は以下の通りです。
- サーバーを起動しなくともテスト結果に影響が出なさそうだ...
- サーバーを起動するとMockMvcが使えなくなり、記法を変更す...
-- MockMvcの代替1 : TestWebClient
--- 利点 : サーバーの起動・非起動に関わらず使用可能
--- 欠点 : WebFluxとかいう未知技術, RepositoryがFlux対応...
-- MockMvcの代替2 : TestRestTemplate
--- 利点 : RestTemplateと同様に使える
--- 欠点 : ''将来的にRestTemplateともども廃止予定''
全体結合テストの手順の例は以下の通りです。
- TestEntityManagerでDBを初期化する。
- MockMvcで疑似REST呼び出しを行い、アサーションを行う
- DBの中身をRepositoryで呼び出し、アサーションを行う
** テストで使用するライブラリの簡単な使い方 [#cd810d25]
*** JUnit5 [#w8214240]
// テストメソッド
@Test
void testMethod(){
// テスト内容
}
// 各テスト前に実行するメソッド
@BeforeEach
void beforeEach(){
// DBの初期化等
}
class AllTests{
// 入れ子クラスをテスト対象にする
@Nested
class HalfTests{
@Test
void testMethod(){
// テスト内容
}
}
}
// テストクラスで様々な拡張機能を使用可能にする
@ExtendWith(...Extension.class)
public class TestClass {
// テスト
}
*** AssertJ [#i285d123]
// アサーションメソッドを静的インポートする
import static org.assertj.core.api.Assertions.*;
// aとbが一致するかチェック
assertThat(a).isEqualTo(b);
// 真偽値をチェック
assertThat(a).isTrue();
assertThat(b).isFalse();
// 例外チェック
assertThatThrownBy(() -> {
// 例外が発生する処理
}).
isInstanceOfSatisfying(
/* 正しい例外クラス */,
(e) ->{
// 発生した例外eが満たすべき条件のアサーションを記...
}
);
*** Mockito(BDD) [#k763d9ab]
// BDDMockメソッドの静的インポート
import static org.mockito.BDDMockito.*;
//JUnit5でモックの作成・注入を可能にする
@ExtendWith(MockitoExtension.class)
public class TestClass{
// モックを使ったテスト
}
// モック
@Mock
private SubService sub;
// 内部でモックを利用する(=モックを注入される)
@InjectMocks
private Service service;
// 注入先での動作を定義する
// service.myMethod(a)が呼ばれるとbを返す
given(service.myMethod(a)).willReturn(b);
// service.myMethod()の引数にMyClass型が渡されるとcを返す
given(service.myMethod(any(MyClass.class))).willReturn(c);
** 今後の積み残し [#m1c4c104]
- 外部API呼び出しのモック
- サービス間連携でのテスト
ページ名: