- プロジェクトリーダー
- Project Manager
- Others
- Other occupations (3)
- Development
- Business
- Other
バックエンドエンジニアの奥村です。
今回はSpringBootでserviceのテストをする際にモックを使った方法を紹介します。
モックをなぜ使うか
ユニットテスト(単体テスト)を行うときに、テスト対象のメソッド内にまだ実装完了していないクラスやメソッドがあるとき、モックを当て込めば指定した値を返すので、テストが可能になります。そのため、テストファーストの実装ではモックを使って効率的に実装を進めることができると思います。
mockitoについて
mockitoはユニットテストのモックフレームワークです。依存関係にあるクラスをモックすることができます。
コントローラ > サービス > DAOという構成の場合にコントローラのテストではサービスをモックすることができ、サービスのクラスではDAOをモックするという形になります。サービスの中で別のサービスをautowiredしている場合はそれもモックすることができます。
サービスのモックを説明
springBootのモックの記事はコントローラのテストをメインに解説していることが多かったので、サービスクラスのテストでモックを使うパターンについて解説します。
今回は単純に従業員テーブルと売上テーブルがあり、従業員の売上平均を求めるメソッドをサービスクラで定義しています。
以下のようにItemService.classを定義します。この時、SalesDaoのクラスは実装済みだが、EmployeeDaoのgetCountメソッドは処理が未完了であるとします。
@Service
class ItemService {
// 売上テーブルにアクセスする
@Autowired
private SalesDao salesDao;
// 従業員テーブルにアクセスする
@Autowired
private EmployeeDao employeeDao;
// 従業員の売上平均を求める処理
public int getSalesAve(){
int AllSales = salesDao.getAllsales();
int count = employee.getCount();
int SalesAve = AllSales / count;
return SalesAve;
}
}@Service
class ItemService {
// 売上テーブルにアクセスする
@Autowired
private SalesDao salesDao;
// 従業員テーブルにアクセスする
@Autowired
private EmployeeDao employeeDao;
// 従業員の売上平均を求める処理
public int getSalesAve(){
int AllSales = salesDao.getAllsales();
int count = employee.getCount();
int SalesAve = AllSales / count;
return SalesAve;
}
}
モック化する必要があるのはemployeeDaoのgetCountメソッドになります。
そのためサービスのテストクラスではmockitoを使ってgetCountメソッドが呼び出される処理では予め任意の値を返すように記述します。以下がサービスのテストクラスです。
@ExtendWith(SpringExtension.class) // junit5でテストクラスに指定するアノテーション
@AutoConfiureMockMvc // MockMvc の自動設定を有効にして設定するためにテストクラスに適用できるアノテーション
class TestItemService {
private int count;
@Mock // モック化するアノテーション
private EmployeeDao employeeDao;
@InjectMocks // モックが挿入対象になるアノテーション
private ItemService itemService;
@BeforeEach // テスト実行前に実行されるアノテーション
private void setup(){
// モックの初期化
MockitoAnnotations.openMocks(this);
this.count = 5;
}
@Test
public void getSalesAve(){
// モックの期待する返却値を設定
when(this.employeeDao.getCount).thenReturn(this.count);
// テストを実行
int SalesAve = itemService.getSalesAve():
// テスト結果を検証
assertThat(SalesAve, is(2000000));
}
}
@ExtendWith(SpringExtension.class) // junit5でテストクラスに指定するアノテーション
@AutoConfiureMockMvc // MockMvc の自動設定を有効にして設定するためにテストクラスに適用できるアノテーション
class TestItemService {
private int count;
@Mock // モック化するアノテーション
private EmployeeDao employeeDao;
@InjectMocks // モックが挿入対象になるアノテーション
private ItemService itemService;
@BeforeEach // テスト実行前に実行されるアノテーション
private void setup(){
// モックの初期化
MockitoAnnotations.openMocks(this);
this.count = 5;
}
@Test
public void getSalesAve(){
// モックの期待する返却値を設定
when(this.employeeDao.getCount).thenReturn(this.count);
// テストを実行
int SalesAve = itemService.getSalesAve():
// テスト結果を検証
assertThat(SalesAve, is(2000000));
}
}
ポイントは@AutoConfiureMockMvc、@Mock、@InjectMocks、MockitoAnnotations.openMocks(this)です。
@AutoConfiureMockMvcをテストクラスに設定することでMockを使用できるようになります。
@Mockは今回未実装のemployeeDaoのメソッドをモック化しています。
@injectMocksが@Mockが挿入される対象になります。
テスト実行前にMockitoAnnotations.openMocks(this)を実行することでモックの初期化を実行します。
このように実装することで、テストファーストの際にモックを使用することで、他の実装の兼ね合いでまだ未実装なメソッドなどを意識せずに開発を進めることができます。
モックを使って快適テストファーストな実装をしていきましょう。