単体テストの効率的な作成
Java開発において、IntelliJ IDEAなどのIDEを使用している場合、Command + Shift + T(Windows/LinuxではCtrl + Shift + T)のショートカットを利用することで、対象クラスに対応するテストクラスを素早く生成できます。
MockMvcを利用したコントローラーのテスト
Spring BootのMVCレイヤーをテストする場合、MockMvcを使用してHTTPリクエストをシミュレートするのが一般的です。以下に、リクエストヘッダーやJSONペイロードを含むテストの構成例を示します。
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.nio.charset.StandardCharsets;
@SpringBootTest
class ApiControllerTest {
@Autowired
private WebApplicationContext webContext;
private MockMvc mockMvc;
@BeforeEach
void setup() {
// MockMvcの初期化
mockMvc = MockMvcBuilders.webAppContextSetup(webContext).build();
}
@Test
void verifyGetEndpoint() throws Exception {
MvcResult result = mockMvc.perform(
MockMvcRequestBuilders.get("/api/v1/status")
.header("X-Custom-Header", "TestValue")
.contentType(MediaType.APPLICATION_JSON)
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
System.out.println("Response: " + responseBody);
}
}
Mockitoによる依存コンポーネントのモック化
サービス層の依存関係を切り離してテストする場合、Mockitoを使用します。Spring Boot環境では、@MockBeanを使用することで、Springコンテキスト内のBeanをモックに差し替えることが可能です。
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@SpringBootTest
public class OrderServiceTest {
@MockBean
private PaymentGateway paymentGateway;
@Autowired
private OrderService orderService;
@Test
public void processOrderTest() {
// モックの振る舞いを定義
Mockito.when(paymentGateway.authorize(Mockito.anyDouble()))
.thenReturn("AUTH_SUCCESS");
String status = orderService.completeOrder(1001L);
assert "COMPLETED".equals(status);
}
}
Mavenを利用している場合、以下の依存関係をpom.xmlに追加してテスト環境を構築します。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
JUnit 5の主要なアノテーション
JUnit 5(Jupiter)では、テストのライフサイクルを管理するために以下のアノテーションが用意されています。
- @Test: メソッドをテストケースとして定義します。
- @BeforeEach / @AfterEach: 各テストメソッドの実行前後に処理を行います。
- @BeforeAll / @AfterAll: 全テストメソッドの実行前後に一度だけ処理を行います(staticメソッドである必要があります)。
- @DisplayName: テスト結果に表示されるカスタム名を指定します。
- @Disabled: テストの実行をスキップします。
- @Timeout: 実行時間が指定を超えた場合に失敗させます。
アサーション(検証)メソッド
テスト結果が期待通りであるかを確認するために、多様なアサーションメソッドが提供されています。
| メソッド | 説明 |
|---|---|
| assertEquals | 期待値と実際の値が等しいか検証 |
| assertNotSame | オブジェクトの参照先が異なるか検証 |
| assertTrue / assertFalse | 条件が真または偽であるか検証 |
| assertNotNull | オブジェクトがnullでないか検証 |
| assertThrows | 特定の例外が発生するか検証 |
| assertTimeout | 指定時間内に処理が終了するか検証 |
高度なテスト手法
入れ子(Nested)テスト
@Nestedアノテーションを使用すると、関連するテストをグループ化して階層構造にでき、可読性が向上します。
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class ShoppingCartTest {
@Nested
class WhenEmpty {
@Test
void totalItemCountShouldBeZero() {
// 検証ロジック
}
}
@Nested
class WhenItemsAdded {
@Test
void totalItemCountShouldIncrease() {
// 検証ロジック
}
}
}
パラメータ化テスト
同じテストロジックを異なる入力値で繰り返し実行したい場合、@ParameterizedTestを利用します。
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertNotNull;
class ValidationTest {
@ParameterizedTest
@ValueSource(strings = {"Alice", "Bob", "Charlie"})
void testWithNameInputs(String name) {
assertNotNull(name);
System.out.println("Checking: " + name);
}
}