1. ホーム

[解決済み】例外がスローされないことをテストする方法は?

2022-03-26 13:34:21

質問

というのも一つの方法だとは思いますが。

@Test
public void foo() {
   try {
      // execute code that you expect not to throw Exceptions.
   } catch(Exception e) {
      fail("Should not have thrown any exception");
   }
}

何かもっと簡単な方法はないでしょうか?(おそらくJunitの @Rule ?)

解決方法は?

アプローチの仕方が間違っています。もし例外が投げられたら、テストは自動的に失敗します。例外がスローされない場合、テストはすべて緑色になります。

この質問には時々関心があるようなので、少し話を広げます。

ユニットテストの背景

ユニットテストを行う場合、何をもって1つの作業単位と考えるかを自分自身で定義することが重要です。基本的には、コードベースから抽出したもので、複数のメソッドやクラスが含まれていてもいなくても、ひとつの機能を表すものです。

または、以下のように定義されています。 ユニットテストの技術 第2版 ロイ・オシェロブ著 11ページ

<ブロッククオート

A 単体テスト は、テストされる作業単位を呼び出して、その作業単位の最終結果に関するいくつかの仮定をチェックする自動化されたコードの一部です。ユニットテストは、ほとんどの場合、ユニットテストフレームワークを使って書かれます。ユニットテストは、簡単に書くことができ、素早く実行することができます。信頼性が高く、読みやすく、保守しやすい。プロダクションコードが変更されていない限り、その結果には一貫性があります。

重要なのは、1つの ユニットワーク 通常、1つのメソッドだけでなく、非常に基本的なレベルでは1つのメソッドであり、その後、他の作品単位にカプセル化されます。

理想的なのは、個別の作業単位ごとにテストメソッドを用意し、どこで問題が起きているのかを常に確認できるようにすることです。この例では、基本的なメソッドである getUserById() はユーザーを返し、合計3つのユニットオブワークがあります。

最初の作業単位は、有効な入力と無効な入力の場合に、有効なユーザーが返されるかどうかをテストする必要があります。

データソースがスローする例外は、すべてここで処理しなければなりません。 ユーザーが存在しない場合は、ユーザーが見つからないときに例外がスローされることを示すテストが必要です。そのサンプルとして IllegalArgumentException でキャッチされる @Test(expected = IllegalArgumentException.class) アノテーションを使用します。

この基本的な作業単位ですべてのユースケースを処理したら、レベルを上げていきます。ここでは、まったく同じことを行いますが、現在のレベルのすぐ下のレベルに由来する例外のみを処理します。こうすることで、テストコードの構造が保たれ、あちこちに飛び回ることなく、アーキテクチャを素早く実行して、どこで問題が発生したかを見つけることができます。

テストの有効入力と異常入力の処理

この時点で、これらの例外をどのように処理するかは明確になっているはずです。入力には2つのタイプがあります。 有効 入力と 不具合 の入力(入力は厳密な意味では有効だが、正しくない)。

で作業する場合 有効 を入力すると、どんなテストを書いてもうまくいくことを暗黙のうちに期待していることになります。

このようなメソッド呼び出しは、次のようなものになります。 existingUserById_ShouldReturn_UserObject . もしこのメソッドが失敗したら(例えば例外が投げられたら)、何かがうまくいかなかったとわかるので、調査を始めることができます。

別のテスト( nonExistingUserById_ShouldThrow_IllegalArgumentException を使用します。 不具合 を入力し、例外を期待することで、間違った入力に対してメソッドが想定したとおりに動くかどうかを確認することができます。

TL;DR

あなたのテストでは、有効な入力と欠陥のある入力をチェックするという2つのことを行おうとしていました。これを 2 つのメソッドに分割し、 それぞれがひとつのことを行うようにすれば、より明快なテストができ、 どこで問題が発生するのかをよりよく把握することができます。

階層化された作品単位を念頭に置くことで、階層が上のレイヤーで必要なテストの量を減らすこともできます。なぜなら、下のレイヤーでうまくいかなかったかもしれないことをすべて考慮する必要がないからです。現在のレイヤーより下のレイヤーは、依存関係が機能していることを事実上保証しており、もし何かがうまくいかないなら、それは現在のレイヤーにあります(下のレイヤー自身がエラーを投げないと仮定してですが)。