🐞
Repositoryクラス、ServiceクラスのJUnitを使った単体テストについて。
はじめに
- Springboot初学者です。
- JUnitを使ったテストを実装していますが、理解が不足しているので理解を深めるためにアウトプットします。
- 自分のためのメモ感覚でまとめていきます。
- 今回、Controllerクラスのテストについては省略させていただきます。
- 内容に誤り等あれば教えてください。
開発環境
- Springboot
- JUnit
アノテーションの使い方。
- Mock用のアノテーションは後述します。
@SpringBootTest
- 実際のアプリケーションと同様の環境でテストを行うことができます。
-
webEnvironment=RANDOM_PORT
を使用してランダムポートでサーバーを起動することに注意してください(テスト環境での競合を回避するのに便利です)
@Test
- 各メソッドにアノテーションをつけます。そのメソッドがテストとして実行されます。
@BeforeEach
, @AfterEach
- 各テスト(@Test等)が実行される前後に実行されるメソッド。
- JUnit4の@Before, @Afterと類似したものです。
@BeforeAll
, @AfterAll
- 全テスト(@Test等)が実行される前後に実行されるメソッド。
- JUnit 4の@BeforeClassと類似したものです。
- 基本的にstaticでないといけない。
@Sql("/test.sql")
- クラスの前にアノテーションをつけた場合は全テスト実行に前に実行される。
- 各テストの前にアノテーションをつけた場合は各テスト実行に前に実行される。
-
/test/resouces/
の下に配置されたSQLファイルを呼び出す。 - 複数のSQLファイルを実行することもできる。
@Sql({"/test.sql", "/test-user-data.sql"})
@Transactional
- テストメソッドに @Transactional アノテーションを付けると、トランザクション内でテストが実行され、デフォルトでは、テストの完了後に自動的にロールバックされます。
- テストクラスに @Transactional アノテーションが付けられている場合、そのクラス階層内の各テストメソッドはトランザクション内で実行されます。
@DisplayName
- @DisplayNameをつけると、テスト実行時に実行名が表示される。
@Test
@DisplayName("User情報が削除できているか確認するテスト。")
void testDelete() {
- ログへの出力結果。
testDelete(com.example.demo.controller.UserControllerTest),false,1,false,2,Userの退会処理を確認するテスト。,,[engine:junit-jupiter]/[class:com.example.demo.controller.UserControllerTest]/[method:testDelete()]
アサーションメソッド
アサーション | 説明 |
---|---|
asserNUll |
値がnullであることを確認します。 |
assertEquals |
二つの値が正しいことを確認します。 |
assertNotEquals |
二つの値が異なることを確認します。 |
- 他のアサーションメソッドは下記リンク参照。
https://junit.org/junit4/javadoc/4.13/org/junit/Assert.html
Mockとは
- テストを行う際に実際のデータを使わずに検証を行うことができる。
- 独立してテストを行うことができる。
Mockitoとは
- Mockを使うためのフレームワーク。
使われるアノテーション
@Mock
- モックオブジェクトを作成する。
@Mock
private UserRepository userRepository;
@InjectMock
- テストの対象とするクラスの変数に付与する。
@InjectMocks
private UserService userService;
@Captor
- ArgumentCaptorオブジェクトを生成時に使用する。
- verifyメソッドを使用する際、引数にArgumentCaptorを渡すことができる。
ArgumentCaptor<String> fruitCaptor = ArgumentCaptor.forClass(String.class);
verify(mockCounter).countFruits(fruitCaptor.capture());
List<String> capturedFruits = fruitCaptor.getAllValues();
List<String> expectedFruits = Arrays.asList("Apple", "Banana");
assertEquals(expectedFruits, capturedFruits);
@ExtendWith
- 独自Extensionクラスを適応させるときに使用する。
<!-- 例:独自で作成した `CustomTestSupportExtension`クラスを適応させる。 -->
@ExtendWith(CustomTestSupportExtension.class)
class YourTest {
CustomTestSupport support;
@Test
void test() {
}
}
その他のアノテーションについておすすめ記事。
MockMvcとは
- コントローラーのテストをするためのツール。
- サーバやデータベースを用意する手間を省くことができる。
使われるアノテーション
@WebMvcTest
- Controllerのユニットテストを行うときに使用します。
- デフォルトでは、@WebMvcTest アノテーションが付けられたテストは、
Spring Security
およびMockMvc
を自動構成します。 - 通常、@WebMvcTest は
@MockBean
または@Import
と組み合わせて使用されます。 - アプリ全体をテストする場合は、このアノテーションではなく
@SpringBootTest
と@AutoConfigureMockMvc
の使用を検討する必要があります。
@AutoConfigureMockMvc
- アプリケーション全体をテストすることができる。
@AutoConfigureMockMvc(addFilters = false)
- Sring Security等のフィルターによりテストが実行できない時に、
addFilters = false
を行うことでSpring Securityのフィルターを外すことができる。
WebMvcTestの詳細については下記のリンクを参照。
実装例
Repositoryクラスのテスト(Mockなし)
@SpringBootTest
@Sql("/test.sql")
@Transactional
public class UserRepositoryTest {
@Autowired
private UserRepository repository;
@Test
@DisplayName("RegisterUserFormの情報から登録処理ができているかのテスト。")
void testInsert() {
RegisterUserForm form = new RegisterUserForm("taro", "taro@taro", "taro");
Integer userId = repository.insert(form);
User user = repository.load(userId);
assertEquals(user.getName(), "taro");
}
}
Serviceクラスのテスト(Mockあり)
- Serviceクラスのdelete処理で、Mockは削除できない。からverifyで確認。
@ExtendWith(MockitoExtension.class)
@Transactional
public class UserServiceTest {
@Mock
private UserRepository repository;
@InjectMocks
private UserService service;
@Test
@DisplayName("idからUser情報を取り出すテスト。")
void testLoad() {
User user = new User(1, "taro", "demo_user@example.com", "password", "hello", LocalDateTime.now(), LocalDateTime.now());
doReturn(user).when(repository).load(1);
User result = service.load(1);
assertEquals(result.getName(), "taro");
verify(repository, times(1)).load(1);
}
}
-
doReturn(user).when(repository).load(1);
repository.load(1)
メソッドを使う時に、user
を返すように指定。 - 戻り値がnullの時は、
do
から始まる文を使う。 -
verify(モックインスタンス, times(想定回数)).メソッド(引数);
テスト時にメソッドがtimes
の回数だけ実行されたことを確認する。
VSCodeで簡単にテストを作成する方法。
- ソースコードを開く。(例:UserService.java)
- ソースコード上で右クリックし、「ソース アクション」を選択。
- 一番上の
Generate Test...
を選択。 - テスト実行用クラスの名前を入力。
- テストを行うメソッドを選択し、OKをクリック。
- 簡単にテストファイルが作成される。(例:UserServiceTest.java)
参考文献
土岐 孝平. プロになるためのSpring入門ーーゼロからの開発力養成講座 Software Design plus (p. 461). (Function). Kindle Edition.
Discussion