ネガティブテストを記述する
学習の目的
この単元を完了すると、次のことができるようになります。
- ネガティブ単体テストとは何かを説明する。
- ネガティブ単体テストを記述する。
ネガティブ単体テストを記述する理由
ネガティブテストというと、とても…否定的な響きがしますが、多くの開発者はネガティブテストの重要性を確信しています。次の動画で、ネガティブテストの概要と実行する理由をご覧ください。
ネガティブ単体テストの用途は、コードの全行がテストされたことを確認するだけではありません。実際のところ、ネガティブテストのほうがポジティブテストよりも重要なことがあります。ネガティブテストでは、無効なデータ、予期しないユーザー入力、コードベースの他の部分の変更がコードで適切に処理されているかどうかが示されます。さらに重要な点は、記述したコードの耐障害性がネガティブテストで確認されることです。
コードで例外がどのように処理されるかをテストすることは、妥当な条件下でコードが意図したとおりに機能することを確認するのと同じくらい重要です。一括処理を想像してみてください。コードが毎晩午前 2 時に、カスタマーコミュニティで取引先責任者が入力した取引先の更新情報を処理するとします。コードが一括処理の最初のレコードで失敗し、例外を適切に処理しなければ、残りのレコードが処理されません。ネガティブテストを実行すれば、こうした状況を未然に防ぐことができます。
パターン
ポジティブテストでは、有効な入力を使用してコードをテストし、コードが適切に機能した場合にどうなるかが示されます。ネガティブテストの場合は、コードが無効なデータや例外を適切に処理することが示されます。こうしたテストは、必ずしも容易に達成されるとは限りません。単体テスト中に例外がスローされれば、そのテストが失敗となるためです。
では、コードが例外をスローすれば合格となるテストを記述するにはどうすればよいでしょうか? さらに重要な点は、さまざまな例外種別が使用される中で、コードが期待どおりの種別の例外をスローした場合にのみ合格とするテストを記述するにはどうすればよいのでしょうか? ネガティブテストの一般的なパターンは次のようになります。
- テストデータを生成するか読み込みます。
- try/catch ブロックを開始します。
Test.startTest()
をコールします。- コードを実行します。
Test.stopTest()
をコールします。- 例外が期待どおりスローされるようにします。このために、必ず失敗する assert を次の行に追加します。このステートメントに達することはありません!
- 期待どおりの例外をキャッチし、例外メッセージが一致しているかどうか確認します。
この例の AccountWrapper
クラスに、例外をスローするコード行があります。この動作を実行するテストは次のようになります。
- VS Code を開きます。
- [Explorer (エクスプローラー)] サイドバーで、
classes
フォルダーをクリックします。 - [AccountWrapperTests] クラスを選択します。
- クラスの終了前に、次のコードを追加します。
- [File (ファイル)] > [Save (保存)] をクリックします。
- 作業中のファイルを右クリックして、[SFDX: Deploy Source To Org (SFDX: 組織にソースをリリース)] を選択します。
testNegativeAccountWrapperAvgPriceOfOpps
メソッドに表示される [Run Test (テストを実行)] ボタンをクリックします。
コードのポイント
このテストでは、@TestSetup
メソッドが作成した商談を基に構築していきます。ただし、AccountWrapper
が無効なデータをどのように処理するかをテストするには、@TestSetup
メソッドが作成した商談の金額がすべて 0 であることを確認する必要があります。このために、テストに for ループを使用して各商談を反復処理し、金額項目を 0 に設定します。 テストデータをこのように設定すると、AccountWrapper の getRoundedAvgPriceOfOpps()
メソッドが、すべての商談の四捨五入された価格を 0 と算出します。その結果、コードが AWException (AccountWrapper クラスで定義されたカスタムの例外種別) をスローします。単体テストで、この AWException オブジェクトをキャッチします。
このような try/catch ブロックの問題は、適切に記述されていなければ、catch ブロックが例外の何らかのインスタンスまたはサブクラスをキャッチしてしまうことです。このベストプラクティスは、例外をキャッチしたときに、例外種別と例外のメッセージや詳細が期待どおりのものであることをテストで確認することです。この例では、AccountWrapper クラスで定義されている AWException というカスタムの例外種別が期待されています。
コードに、例外をスローする可能性がある場所が複数あり、同じ種別の例外がスローされることも少なくありません。たとえば、validate メソッドが設定されている ContactService
クラスの 3 ~ 4 か所で、異なる理由により ContactServiceException
がスローされることがあります。テストで種別、メッセージ、詳細をチェックしなければ、誤って合格してしまうおそれがあります。これを偽陽性といい、偽陽性が多すぎると、テストの信頼性が損なわれる可能性があります。