web-dev-qa-db-ja.com

voidメソッドのユニットテスト

アプリケーションのバグを修正するために、postLoginという名前の既存のメソッドへの呼び出しを追加して、getShoppingCartという名前のメソッドを変更しました。

コード

protected void postLogin() {
  getShoppingCart();
}

ただし、postLoginの単体テストを記述する最善の方法は何なのかわかりません。

アプローチ1

Mockitoのverifyを使用して、メソッドが呼び出されたことを確認します。

verify(mock).getShoppingCart();

アプローチ2

ユーザーのショッピングカートの値をフェッチして、メソッド呼び出しの副作用をテストします。

AssertNotNull(user.getShoppingCart());

一方のアプローチが他方よりも優れていますか?

15
A_B

私は通常方法2を好みます。

どうして? postLoginでシステムの一部の状態を変更したいのですが、これを実現する方法(およびこのために内部で呼び出すメソッド)は実装の詳細にすぎないため、ユニットテストでは何も想定すべきではありません。したがって、最終状態を確認するだけでテストを行う方がよいでしょう。

18
Doc Brown

私はgetShoppingCartをinitializeShoppingCartのようなものに変更します。メソッドの目的は、メソッドの動作を確認する必要なく誰でも読むことができ、このような副作用がメソッドのユーザーに驚くべき動作を引き起こす可能性があります。

GetShoppingCartが別のクラスにあり、すでにユニットテストされている場合は、アプローチ1を使用します。すでにテストされているものを再度テストする必要はありません。この場合、getShoppingCartが適切に動作していることを確認し、それがpostLoginから呼び出されることのみを確認したいので、将来誰かがこの呼び出しを削除した場合、テストは失敗します。

GetShoppingCartがそれ自体ではテストできないプライベートメソッドである場合は、アプローチ2を使用して、postLoginが呼び出されたときにgetShoppingCartの必要な機能が期待どおりに実行されることを確認します。

4
Nastya S

副作用のある関数呼び出し(voidかどうかにかかわらず)をテストする場合、副作用が発生するだけでなく、副作用(システム出力または状態変化)が望ましいものであることを確認することをテストするのが最も完全です。

1
hotpaw2

私はあなたのデザインについては触れませんが、ユニットテストはドメイン内での仕事に関係なく技術的に何を行うか、つまりあなたのメソッドがpostLoginを行うことをテストするため、最初のアプローチに行きます?技術的にはgetShoppingCardを呼び出すので、実際にgetShoppingCardを呼び出しているかどうかをテストする必要があります。getShoppingCardの別のテストを作成して、それが何を行うか、および副作用があるかどうかをテストします新しいテストで確認します。

0
La VloZ Merrill

PostLoginにバグがあります。したがって、最初に行うべきことは、予想される情報セットなしでpostLoginを呼び出すと「失敗」する単体テストを作成することです。

上記のアイデアから、提案された2の別の代替案は、ショッピングカートに関する情報をパラメーターとして挿入することです。正しい情報がない場合、未チェックの例外がスローされます。これにより、正しい詳細がなければ、メソッドが失敗することが明らかになります。

これには、今すぐpostLoginを呼び出すクライアントがショッピングカート情報も渡す必要があるという小さな変更が必要です。私には、これらが結合されていることがわかりますが、今でも一貫しています。この結合は、呼び出し元によって行われます。

次に、テスト対象の実際のメソッドはpostLoginであるため、postLogin内でgetShoppingCartをテストする必要すらありません。これはバグがあり、適切な修正と検証が必要な唯一の問題です。依存関係を挿入すると、さまざまな条件下で簡単にテストして、エラーがスローされないことを確認できます。

0
gumol