Webサービス呼び出しを必要とするクラスを単体テストするにはどうすればよいですか?

私はいくつかのHadoop Webサービスを呼び出すクラスをテストしようとしています。コードはほとんど次のような形式です。

method() {
    ...use Jersey client to create WebResource...
    ...make request...
    ...do something with response...
}

例えばディレクトリ作成方法、フォルダ作成方法などがあります。

コードが、私が制御できない外部Webサービスを扱っていることを考えると、どうすればこれを単体テストできますか?私はWebサービスのクライアント/応答をモックすることができましたが、それは私が最近見たガイドラインを壊します:「あなたが所有していないオブジェクトをモックしないでください」。ダミーのWebサービス実装をセットアップすることもできます。それでも「単体テスト」を構成するのでしょうか、それとも統合テストになるのでしょうか。この低いレベルで単体テストを行うことは不可能なのですか - TDDの専門家はどのようにこれに取り組むのでしょうか?

18
自分が所有していないものをあざけらないようにするための手引きをどこで見ましたか?それはあなたが物事をモックするべきである大きな理由のようです...
追加された 著者 Joel Spolsky,
@ChrisCooper:最後のリンクが(2007年から)非常に古くなっていることを指摘してください。それ以来、たくさんのことが変わりました。単にモックフレームワークやメタプログラミングを使用して戻り値を設定するのではなく、実際に動作を実装しなければならなかったとき、モックははるかに難しかったという投稿から私は感じます...
追加された 著者 c_maker,
私はたくさんのブログでそれを読んでいますが、そのうちの1つは amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/‌… 私が知っているのはよく知られた本です( blog.8thlight.com/eric-smith/2011/10/27/thats- not-yours.htm‌ lmockobjects.com/2007/04/test-smell-everything-is-mocked.html ‌)
追加された 著者 telent,

5 答え

私の考えでは、統合テストとは対照的に、これが単体テストである場合は、Webサービス呼び出しを模擬する必要があります。

単体テストでは、外部Webサービスが機能しているかどうか、またはそれとの統合が正しいかどうかをテストしないでください。 TDDについてあまり批判的にならずに、単体テストを統合テストに変えることの副作用はそれがより遅く実行される可能性があることであり、あなたは速い単体テストを望んでいることに注意してください。

また、Webサービスが一時的に停止しているか、正しく機能していない場合、これで単体テストが失敗する可能性がありますか?正しくないようです。あなたのユニットテストはたった一つの理由で失敗するべきです:その "ユニット"のコードにバグがあるなら。

ここで関係のあるコードの唯一の部分は ...応答で何かをする... です。残りを嘲笑しなさい。

38
追加された
Hadoopのような市販のコンポーネントをテストする価値はほとんどありません。しかし、もしあなたが他のチームや組織によって提供されたカスタムWebサービスを呼んでいるのなら、あなたはそれを自己防衛でテストしたいと思うかもしれません。そうすれば、問題が発生したときに、問題が自分のコードなのかWebサービスなのかをすぐに確認できます。これは自動的に実行される単体テストではありません。必要に応じて実行するのは診断的です。
追加された 著者 miguel.de.icaza,
@AndresF .:私たちは暴力的な一致にあると思います: "これは[診断]は単体テストではありません..."
追加された 著者 miguel.de.icaza,
@kevincline私はあなたが提案するテストの必要性に完全に同意します、そして確かに私は彼らの日々の仕事の中でそれらを書き、そしてそれら自身が有用であることを証明しました。しかし、それらは定義上単体テストではありません。これが問題です:)これを考慮してください。それが単体テストで、Webサービスが変更されたためにコードが失敗する場合、テストしている「単体」は何ですか。正確に何が失敗しましたか?単体テストで必要とされるように、あなたは単独ではテストしていません。
追加された 著者 Mike McAllister,
@ kevinclineそうだね!あなたのコメントを読み間違えました、ごめんなさい!
追加された 著者 Mike McAllister,
素晴らしいアドバイスです。実際に利用可能な唯一のもの!
追加された 著者 varun,
モックオブジェクトのシグネチャと戻り値を、Hadoop Webサービスによって生成されたものと同期させる必要があることを忘れないでください。
追加された 著者 catalpa,

あなたが単体テストをしているとき、私は「あなたが所有していないオブジェクトを偽装しないでください」とは反対です。

モックの存在目的は私達が所有しないモジュール、ライブラリ、クラスがあるという事実です。

あなたのシナリオに対する私の提案は、Webサービス呼び出しを偽造することです。

モジュールにデータが返されるようにモックを設定します。
返されたデータがnullの場合、返されたデータが有効な場合など、必ずすべてのシナリオを網羅してください。

そしてあなたが所有するコードに関して、開発者としてのあなたの責任はあなたがオーサリングしているコードがすべてのシナリオで期待通りに動作することを保証することです。

5
追加された

このテストにはEasyMockのようなものを使います。モックフレームワークは、クラスの外部依存関係を削除するのに理想的な方法であり、テスト中に外部依存関係の結果を完全に制御できます。あなたの例を少し拡張するには:

class WebClass {

private WebServiceInterface webserviceInterface;

    void method(){
        R result = webServiceInterface.performWebServiceCall();
        ... do something with result
    }

    public void setWebServiceInterface(WebServiceInterface webServiceInterface){
        this.webServiceInterface = webServiceInterface;
    }
}


interface WebServiceInterface {

   R performWebServiceCall();

}


class WebClassTest {

private WebServiceInterface mock;    
private R sampleResult = new R();

    @Before
    public void before(){
        mock = EasyMock.createMock(WebServiceInterface.class);
    }


    @Test
    public void test() {
        WebClass classUnderTest = new WebClass();
        EasyMock.expect(mock.performWebServiceCall()).andReturn(sampleResult);
        classUnderTest.setWebServiceInterface(mock);
        classUnderTest.method();
        EasyMock.verify(mock);
    }
}

最初にする必要があるのは、Jerseyを使用してWebResourceを取得し、Webサービスを別のクラスに呼び出すクラスからロジックを抽出することです。このクラスのインターフェースを作成することで、モックを作成してそれに動作を指示することができます。

このインターフェースが作成されたら、EasyMockを使用してモックを作成できます。これにより、テストケースに一致する特定のオブジェクトが返されます。上記の例は、基本的なモックテストを構築する方法とインターフェイスがどのように機能するかを単純化したものです。

モックフレームワークの詳細については、こちらの質問をご覧ください。。また、この例ではJavaの使用を前提としていますが、モックフレームワークはすべての言語で使用可能であり、実装方法は異なりますが、概して同じように機能します。

1
追加された

この場合、モックは受け入れられますが、必要ありません。 method()を単体テストする代わりに、応答を処理する部分だけを単体テストします。

ResponseData を受け取り(適切な種類の)関数を実行してからアクションを実行します。

モックする代わりに、ResponseDataオブジェクトを作成して渡します。

あなたはサービスの呼び出しを完全な統合テストに任せることができます - それは全部で method()をカバーするでしょう

1
追加された

私がしたこと、そしてそれはうまくいく:

  1. すべてのコードでプロキシ経由でWebサービスを呼び出すようにします。
  2. プロキシは、プロキシを使用しているかどうかを静的に認識し、それに応じてリダイレクトするクラスを呼び出します。モックは単なるハッシュマップで、リクエストごとに与えられた返信を返します。
  3. この順序でテストを数回実行します。

3.1最初にすべてのWebサービスがテストされます。各マシンから、さらに開発者のマシンから。これらは本物のWebサービスですが、開発環境で動作しています。そうでなければ、すべての開発者が自分ではコンパイルできないと文句を言うので、Webサービスが停止したり誤った値を返信したりすることは決してあり得ません。

3.2その後、アプリケーション内部のすべての単体テストが実行されます。つまり、すべてのWebサービスはモックされ、3.1と同じテストを実行してテストされ(そうでなければアウトモックも間違っています)、実際のアプリケーションによって実際に使用されているかのように呼び出されます。モックが間違っている場合は、3.1でテストを実行し、それらの(要求、応答)値をHashMapに記録することができます。

3.3その後3.2と同じテストが実行されますが、今回は開発環境で実行されている実際のWebサービスに対して行われます。

これらすべてが完了したら、実際の実稼働環境では、各Webサービスの実際のアドレスを入力するだけで済みます。うまくいけば、これは設定の変更をそれほど必要としません。

0
追加された