7

さて、これは危険な質問かもしれません。私はしばらく単体テストを行っていましたが、何らかの理由で今朝起きて、この質問を自問しました。

インターフェイス UserFactory があり、メソッド CreateUser があるとします。

ある時点で、ユーザー権利を作成する必要がありますか? そこで、適切な場所で UserFactory に対して CreateUser が呼び出されたかどうかを確認するテストを作成します。

これで、単体テストは実際のコードにかなり結合されました。これで問題ありません。でもちょっとやり過ぎかな?このように、テストを中断する唯一の方法は、CreateUser への呼び出しを呼び出さないことです。その実装などはチェックしていませんが、インターフェースが呼び出されていることをチェックしているだけです。しかし、誰がその呼び出しを削除しても、テストは失敗し、最終的にステップから検証ステートメントを削除して、CreateUser が呼び出されたことを確認します。

私はこれが何度も何度も起こるのを見てきました。

誰かが私に光を取り戻して、モックされたオブジェクトのメソッドが呼び出されたことを確認することが有益である理由を説明できますか? CreateUser はコードの後半部分でダミーのユーザーを返す必要があると言いますが、それらが呼び出されたかどうかを単純に確認するだけの場所では、それらを設定すると便利な理由がわかります。

ありがとう!

4

4 に答える 4

2

テストを中断する唯一の方法は、CreateUser を呼び出さないことです。

したがって、少し複雑なメソッド、いくつかの条件などでは、その呼び出しをスキップするのは非常に簡単です。その後のメンテナンスにより、意図せずに通話に失敗する可能性があります。

したがって、これらの副作用のテストには価値があると思います。あなたの場合、常に CreateUser を呼び出す必要がありますか? 例外がスローされた場合はどうなりますか? いくつかの条件で CreateUser が呼び出されないことを確認する値が存在する場合があります。

単純な状況では、私たちのテストとアウトコードが多かれ少なかれ繰り返され、メンテナンスが無意味な「コードを変更し、テストを変更する」アクティビティになると感じることがあることに同意します。パスやエラーハンドリングが多いほど価値が明確になると思います。

于 2012-08-12T18:18:22.030 に答える
2

モックされたオブジェクトを検証することはしばしば必要悪であり、あなたが言及したように、単体テストはテスト対象のクラスに非常に密接に結合されている場合があります。

あなたの質問にうまく答えられるかわかりませんが、やってみます。

userRepository が依存関係であるこのコードを例として取り上げます (この例はあまり良くありません)。

public void doSomething(User user) {
    if( user.isValid() ) {
        userRepository.save(user)
    } else {
        user.invalidate();
    }
}

これをテストする 1 つの方法は、DB に接続する実際のリポジトリを接続し、ユーザーが永続化されていることを確認することです。しかし、私は単体テストを行っているため、テストで外部依存関係を持つことはできません。

では、ユーザーが有効なシナリオを検証するために他に必要なオプションはどれですか? userRepository.save() は void を返すため、副作用を確認する唯一の方法は、モックが呼び出されたことを確認することです。モックを検証しないと、オブジェクトを保存した行を削除しても、テストに合格する可能性があるため、単体テストはあまり適切ではありません。

これは、値を返す一部のモックには当てはまらず、メソッドで値が使用されます。これは通常、モックが null を返す場合、アプリケーションが NullPointerException (Java の場合) をスローすることを意味します。

于 2012-08-12T18:25:58.927 に答える
2

インターフェイスが呼び出されたことを確認するだけでなく、インターフェイスのさまざまな動作について複数のテストを行うことができます。特にまれなケース - CreateUserがエラーを返し、例外が発生したときに、コードは正常にフェールオーバーしますか?

于 2012-08-12T18:15:59.087 に答える
1

テストされたコードで依存関係がどのような目的に役立つかを理解することが重要です。

  • クラスの契約/責任を果たすのに役立ちます(あなたのUserFactory例のように)
  • クラス スコープを超えているが、実行する必要がある作業を委任できるようにする (たとえば、ログ機能がそのようなケースである可能性があります)。

ここで、依存関係 (モック)が役に立たない場合、このヘルプに依存する明らかにテスト済みのコードも失敗します。このような場合、依存関係が呼び出されたことを確認するために追加のテストを行うことはあまり有益ではありません。明確なメッセージでそれに依存するテストでは、呼び出しが複数回失敗することはありません。

工場の例に戻ると、呼び出されないとどうなりますか? 他のいくつかのテスト、おそらくそのユーザーがどこかに保存されているかどうか、またはそれを使用して何かが作成されているかどうかを確認するテストは失敗します。

当然、依存関係の 2 番目のグループがあります。これは、コードにまったく影響を与えず、バックグラウンドで静かに実行するものです。ただし、これらはコードの責任に反映される可能性が最も高く、たとえば次のようになります。

SaveUser メソッドは、新しいユーザーをリポジトリに保存し、操作結果をログに記録する必要があります

通常、適切なメソッドが呼び出されたかどうかを確認する以外に、動作チェックを行う方法はありません。

結論として、テストを作成する必要があるかどうかを判断する際に考慮すべき 2 つの質問があります。

  • このテストは、私のクラスの責任 (の一部) を検証しますか?
  • このテストが成功/失敗したときに、テストされたコードについてどのような知識が得られますか?

必要でない限り、コードが他のコードを呼び出すことをテストしないでください。コードが想定どおりに動作することをテストします

于 2012-08-12T18:49:57.610 に答える