Apex の単体テスト
堅牢で、エラーのないコードの開発を促進するため、Apex は単体テストの作成と実行をサポートします。単体テストは、コード内の特定の部分が正しく機能していることを確認するクラスメソッドです。単体テストのメソッドは引数を取らず、データベースへのデータの確定やメールの送信を行うこともなく、メソッド定義に testMethod キーワードまたは isTest アノテーションでフラグが付けられています。また、テストメソッドは、テストクラス (isTest アノテーションが付加されているクラス) で定義されている必要があります。
1@isTest
2private class myClass {
3 static testMethod void myTest() {
4 // code_block
5 }
6}これは前の例と同じテストクラスですが、代わりに、isTest アノテーションを使用してテストメソッドを定義します。
1@isTest
2private class myClass {
3 @isTest static void myTest() {
4 // code_block
5 }
6}次に、2 つのテストメソッドを含むテストクラスの例を示します。
1@isTest
2private class MyTestClass {
3
4 // Methods for testing
5 @isTest static void test1() {
6 // Implement test code
7 }
8
9 @isTest static void test2() {
10 // Implement test code
11 }
12
13}isTest として定義されたクラスとメソッドは private または public のいずれかと宣言する必要があります。テストクラスメソッドのアクセスレベルを考慮する必要はありません。つまり、テストクラスまたはテストメソッドを定義するときにアクセス修飾子を追加する必要はありません。Apex のデフォルトのアクセスレベルは非公開です。このテストフレームワークでは、アクセスレベルを問わず、常にテストメソッドを検索して、実行することができます。
isTest として定義されたクラスは最上位クラスである必要があるため、インターフェースまたは enum 値とすることはできません。
テストクラスのメソッドは、実行中のテスト、つまり、テストメソッドまたはテストメソッドから呼び出されるコードからのみコールすることができ、テスト以外の要求からコールすることはできません。
この例では、クラスおよび対応するテストクラスを示します。テストするクラスは次のとおりです。この例には、2 つのメソッドとコンストラクタが含まれています。
1public class TVRemoteControl {
2 // Volume to be modified
3 Integer volume;
4 // Constant for maximum volume value
5 static final Integer MAX_VOLUME = 50;
6
7 // Constructor
8 public TVRemoteControl(Integer v) {
9 // Set initial value for volume
10 volume = v;
11 }
12
13 public Integer increaseVolume(Integer amount) {
14 volume += amount;
15 if (volume > MAX_VOLUME) {
16 volume = MAX_VOLUME;
17 }
18 return volume;
19 }
20
21 public Integer decreaseVolume(Integer amount) {
22 volume -= amount;
23 if (volume < 0) {
24 volume = 0;
25 }
26 return volume;
27 }
28
29 public static String getMenuOptions() {
30 return 'AUDIO SETTINGS - VIDEO SETTINGS';
31 }
32
33}これは、対応するテストクラスです。4 つのテストメソッドが含まれています。前のクラスの各メソッドがコールされています。これでテストカバー率は十分ですが、テストクラスのテストメソッドでは、追加のテストを実行して境界の条件を確認します。
1@isTest
2class TVRemoteControlTest {
3 @isTest static void testVolumeIncrease() {
4 TVRemoteControl rc = new TVRemoteControl(10);
5 Integer newVolume = rc.increaseVolume(15);
6 System.assertEquals(25, newVolume);
7 }
8
9 @isTest static void testVolumeDecrease() {
10 TVRemoteControl rc = new TVRemoteControl(20);
11 Integer newVolume = rc.decreaseVolume(15);
12 System.assertEquals(5, newVolume);
13 }
14
15 @isTest static void testVolumeIncreaseOverMax() {
16 TVRemoteControl rc = new TVRemoteControl(10);
17 Integer newVolume = rc.increaseVolume(100);
18 System.assertEquals(50, newVolume);
19 }
20
21 @isTest static void testVolumeDecreaseUnderMin() {
22 TVRemoteControl rc = new TVRemoteControl(10);
23 Integer newVolume = rc.decreaseVolume(100);
24 System.assertEquals(0, newVolume);
25 }
26
27 @isTest static void testGetMenuOptions() {
28 // Static method call. No need to create a class instance.
29 String menu = TVRemoteControl.getMenuOptions();
30 System.assertNotEquals(null, menu);
31 System.assertNotEquals('', menu);
32 }
33}単体テストの考慮事項
単体テストでは、次の点に留意してください。
- Salesforce API 28.0 からは、テストメソッドは非テストクラスに含めることができなくなります。また、isTest アノテーションが付加されているクラスの一部である必要があります。テストクラスから private クラスのメンバーにアクセスする方法については、TestVisible アノテーションを参照してください。
- テストメソッドは、Web サービスコールアウトのテストには使用できません。代わりに、疑似コールアウトを使用します。「Web サービスコールアウトのテスト」および「HTTP コールアウトのテスト」を参照してください。
- テストメソッドからメールメッセージを送信することはできません。
- テストメソッドはテストで作成したデータをコミットしないため、完了時にテストデータを削除する必要はありません。
- テストクラスに静的メンバー変数が含まれ、その変数の値が testSetup またはテストメソッドで変更されている場合は、新しい値が保持されません。このクラスの他のテストメソッドは、静的メンバー変数の元の値を取得します。この動作は、静的メンバー変数が別のクラスで定義され、テストメソッドでアクセスされる場合にも適用されます。
- 一意制約のある項目を含む一部の sObject では、重複する sObject レコードを挿入するとエラーになります。たとえば、同じ名前の複数の CollaborationGroup sObject を挿入すると、CollaborationGroup レコードには一意の名前が必要なためエラーになります。
- Chatter フィードのレコードの追跡変更 (FeedTrackedChange レコード) は、テストメソッドが関連レコードを変更すると、使用できません。FeedTrackedChange レコードでは、作成される前に、関連付けられている親レコードへの変更がデータベースにコミットされている必要があります。テストメソッドではデータをコミットしないため、FeedTrackedChange レコードの作成はできません。同様に、項目履歴管理レコード (AccountHistory など) は、他の sObject レコード (Account など) を最初にコミットする必要があるため、テストメソッドでは作成できません。