Apexのテストは、本番環境でのバグを防ぐ ために欠かせません。
適切なテストを書くことで、アプリケーションの品質を向上 させることができます。
今回は、4つのベストプラクティス について、具体的なコード例 を使って整理しました。
1. データ条件のテストをする(有効、無効、一括など)
✅ 理由
- 本番環境では様々なデータパターンが存在するため、すべてのケースを考慮したテストが必要。
- 有効なデータ(正常系)、無効なデータ(異常系)、一括データ(大量処理)をテストすることで、エラーを未然に防げる。
📌 例:コース開催 (Course_Delivery__c
) の Start_Date__c
のテスト
@isTest
private class CourseDeliveryTest {
// ✅ 1. 正常なデータ(有効な開始日)
@isTest
private static void testValidCourseDelivery() {
Course_Delivery__c courseDelivery = new Course_Delivery__c(
Name = 'Valid Course',
Start_Date__c = Date.today().addDays(10) // ✅ 未来の日付(正常)
);
Test.startTest();
Database.SaveResult result = Database.insert(courseDelivery, false);
Test.stopTest();
System.assertEquals(true, result.isSuccess(), '正常なデータは登録できるはず');
}
// ❌ 2. 無効なデータ(過去の日付でエラー)
@isTest
private static void testInvalidCourseDelivery() {
Course_Delivery__c courseDelivery = new Course_Delivery__c(
Name = 'Invalid Course',
Start_Date__c = Date.today().addDays(-1) // ❌ 過去の日付(エラー)
);
Test.startTest();
Database.SaveResult result = Database.insert(courseDelivery, false);
Test.stopTest();
System.assertEquals(false, result.isSuccess(), '過去の日付のコースは登録できないはず');
}
// 📦 3. 一括データのテスト(10件登録)
@isTest
private static void testBulkInsertCourseDeliveries() {
List<Course_Delivery__c> courses = new List<Course_Delivery__c>();
for (Integer i = 0; i < 10; i++) {
courses.add(new Course_Delivery__c(
Name = 'Bulk Course ' + i,
Start_Date__c = Date.today().addDays(i + 1) // ✅ すべて未来の日付
));
}
Test.startTest();
Database.SaveResult[] results = Database.insert(courses, false);
Test.stopTest();
for (Database.SaveResult result : results) {
System.assertEquals(true, result.isSuccess(), 'すべてのデータは正常に登録されるはず');
}
}
}
✅ 正常系、異常系、大量データ処理のすべてをテストすることで、バグを未然に防げる!
2. クラスとテストクラスは1対1
✅ 理由
- クラスごとに対応するテストクラスを用意すると、管理がしやすくなる。
- どのテストがどのクラスを検証しているのかが明確になる。
📌 ❌ 悪い例(複数の対象クラスを1つのテストクラスで扱う)
@isTest
private class AllTests {
@isTest private static void testCourseDelivery() { /* ... */ }
@isTest private static void testOtherFunctionality() { /* ... */ }
}
⛔ 問題点
- どのクラスのテストなのか不明確 で、コードが煩雑になる。
📌 ✅ 良い例(1つのクラスに対して1つのテストクラス)
@isTest
private class CourseDeliveryTest {
@isTest private static void testValidCourseDelivery() { /* ... */ }
}
✅ 対応関係が明確になり、管理しやすくなる!
3. テストデータが適切に作成されているか
✅ 理由
- 本番環境とSandbox環境ではレコードIDが異なるため、IDをハードコードするとエラーの原因になる。
- テストメソッド内でデータを作成することで、環境に依存しないテストが可能。
📌 ❌ 悪い例(IDをハードコードしている)
@isTest
private class BadTestExample {
@isTest
private static void testWithHardcodedId() {
Course_Delivery__c course = [SELECT Id FROM Course_Delivery__c WHERE Id = 'a0123456789XYZ']; // ❌ IDをハードコード
System.assertNotEquals(null, course);
}
}
⛔ 問題点
- 本番環境とSandboxでIDが異なるため、テストが失敗する可能性がある。
📌 ✅ 良い例(テストデータを動的に作成)
@isTest
private class GoodTestExample {
@isTest
private static void testWithDynamicallyCreatedData() {
Course_Delivery__c course = new Course_Delivery__c(Name = 'Test Course', Start_Date__c = Date.today().addDays(5));
insert course;
Course_Delivery__c retrieved = [SELECT Id FROM Course_Delivery__c WHERE Id = :course.Id];
System.assertNotEquals(null, retrieved, 'コースが存在するはず');
}
}
✅ 環境に依存しない、安定したテストコードになる!
4. SOSL検索のテスト
✅ 理由
- SOSLの検索結果はテスト環境では通常空になるため、明示的に結果をセットする必要がある。
Test.setFixedSearchResults()
を使用して、テストデータの検索結果を指定する。
📌 ✅ 良い例(Test.setFixedSearchResults()
を使用)
@isTest
private class SearchHelperTest {
@testSetup
private static void setupTestData() {
Contact contact1 = new Contact(FirstName = 'Taro', LastName = 'Yamada', Email = 'taro@example.com');
insert contact1;
}
@isTest
private static void testSOSLSearch() {
// 検索結果として返したいレコードのIDをリストに格納
List<Id> expectedIds = new List<Id>();
List<Contact> contacts = [SELECT Id FROM Contact WHERE LastName = 'Yamada'];
if (!contacts.isEmpty()) {
expectedIds.add(contacts[0].Id);
}
// SOSLの検索結果を固定
Test.setFixedSearchResults(expectedIds);
Test.startTest();
List<sObject> results = [FIND 'anytest' IN ALL FIELDS RETURNING Contact(Id, Name)];
Test.stopTest();
System.assertEquals(expectedIds.size(), results.size(), '検索結果の件数が一致するはず');
}
}
✅ テスト環境でも確実にSOSLの検索結果を取得できるようになる!
🎯 まとめ
ベストプラクティス | 理由 | 具体例 |
---|---|---|
1. データ条件のテスト | 正常系・異常系・一括処理を確認 | 未来/過去の日付のバリデーションをテスト |
2. クラスとテストクラスを1対1 | テストの管理がしやすい | CourseDeliveryTest を作成 |
3. レコードIDをハードコードしない | 環境に依存せずにテストできる | insert でデータを作成 |
4. SOSL検索のテスト |
Test.setFixedSearchResults() を使用 |
確実に検索結果を取得 |