web-dev-qa-db-ja.com

保護されたプライベートメソッドのテスト

私はこれを読んでいました answer プライベートメソッドのテストについて、それはいくつかの可能性について言及しました:

  • メソッドを別のクラスのパブリックとして抽出する
  • それらを公開する
  • メソッドがテスト環境でのみ公開されるように、テスト環境と本番環境を分離する

私は現在Javaでコーディングしていますが、コミュニティはJavaおよびおそらく他のいくつかの言語によって提供される一種の仲介の可能性についてどう思いますか? JavaメソッドをProtectedまたはPackageアクセスにすることができるので、非公開でも公開でもなく、JUnitによるテストを可能にする2つの間の何かでもあります。

Google Guavaライブラリは、 "VisibleForTesting"と呼ばれるアノテーションのみを提供しており、テスト目的で保護されている、またはパブリックであると明示的に宣言する以外は何もしません。

この使用法に特化した注釈さえあるので、確かにそれは少なくともコミュニティの一部の間で受け入れられた戦略ですか?

それは許容できる戦略ですか、それとも上記の3つのオプションに固執し、「公開する」戦略と同じと見なす必要がありますか?

9
sam

一般に、保護されたアクセスの使用については、慎重に検討する必要があります。その理由は、ここにある前の質問に対する回答に示されています。 クリーンコードが保護された変数の回避を提案しているのはなぜですか?

それをあなたがここで考える方法で使用することについて-テストするのがより快適に感じられるのでアクセス制限を弱める-それはひどく悪い考えのように見えます。

プライベートメソッドでカバーされる機能をテストするときの「正しいオプション」は、その修飾子をそのままにし、メソッドがプライベートであり続けることを前提に、図のテストアプローチを行うことです。

testability のコードを再設計する必要がある場合、多くの場合と理由が考えられます。単体テストの作成におけるさまざまな困難は、そのようなニーズの良い指標となることがよくあります。しかし、「ああ、そのメソッドはプライベートです」というのは、それらのを示す問題の1つではありません

他の質問と回答は異なる問題に焦点を当てていたので、私は 前の質問への回答 でこれについての説明を付記しました。しかし、あなたが尋ねた質問については、それは完全かつ直接適用されるようですので、私はその部分をここに単にコピーします。


<朗報「私は十分な泣き言を聞いたと思います。大声ではっきり言う時間だと思います... ">

プライベートメソッドは単体テストに有益です。

以下の注は、読者が コードカバレッジ に精通していることを前提としています。そうでない場合は、時間をかけて習得してください。単体テストやテストに興味がある人には非常に役立つからです。

よし、プライベートメソッドと単体テストがあり、カバレッジ分析でギャップがあることがわかったので、プライベートメソッドはテストの対象ではありません。さて...

非公開にすることで何が得られますか

メソッドはプライベートなので、続行する唯一の方法は、コードを調べて、非プライベートAPIを介してそれがどのように使用されるかを学ぶことです。通常、このような調査は、ギャップの理由が特定の使用シナリオがテストに欠けていることであることを明らかにします。

_    void nonPrivateMethod(boolean condition) {
        if (condition) {
            privateMethod();
        }
        // other code...
    }

    // unit tests don't invoke nonPrivateMethod(true)
    //   => privateMethod isn't covered.
_

完全を期すために、このようなカバレッジギャップの他の(頻度は少ない)理由は、仕様/設計のバグである可能性があります。ここでは、物事を簡単にするために、これらについては詳しく説明しません。 「メソッドをテスト可能にするためだけに」アクセス制限を弱めると、これらのバグが存在することを知る機会を逃すことになります。

ギャップを修正するために、不足しているシナリオの単体テストを追加し、カバレッジ分析を繰り返し、ギャップがなくなったことを確認します。私は今何を持っていますか?非プライベートAPIの特定の使用法の新しい単体テストを取得しました。

  1. 新しいテストでは、変更するとテストが失敗するため、この使用法の予想される動作が予告なく変更されないことを確認します。

  2. 外部の読者がこのテストを調べて、 learn がどのように使用され、どのように動作するかを予想します(ここで、外部の読者には私の将来の自己が含まれています。それで終わりました)。

  3. 新しいテストはリファクタリングに耐性があります(プライベートメソッドをリファクタリングしますか?間違いありません!)privateMethodに何をしても、常にnonPrivateMethod(true)をテストしたいと思います。 privateMethodをどのように処理しても、メソッドは直接呼び出されないため、テストを変更する必要はありません。

悪くない?あなたは賭けます。

アクセス制限を弱めることから何を失うか

上記の代わりに、アクセス制限を弱めるだけだと想像してみてください。メソッドを使用するコードの調査をスキップし、exPrivateMethodを呼び出すテストに進みます。すごい?ない!

  1. 上記の非公開APIの特定の使用法のテストを取得できますか?いいえ:以前はnonPrivateMethod(true)のテストはありませんでした。現在、そのようなテストはありません。

  2. 外部の読者は、クラスの使い方をよりよく理解する機会を得ますか?いいえ "-ここでテストされたメソッドの目的は何ですか?-忘れてください、それは完全に内部使用のためです。-おっと。"

  3. リファクタリングに耐性がありますか?まさか、私がexPrivateMethodで変更したものは何でもテストを破るでしょう。名前を変更し、他のメソッドにマージし、引数を変更してテストすると、コンパイルが停止します。頭痛?賭けます!


まとめ、プライベートメソッドを使用すると、単体テストで便利で信頼性の高い拡張機能が得られます。対照的に、「テスト容易性のために」アクセス制限を弱めると、あいまいで理解しにくいテストコードのみが得られます。これは、マイナーなリファクタリングによって破壊される可能性があるという永久的なリスクがあります。率直に言って、私が得たものは疑わしい 技術的負債 のように見えます。

</ rant>

18
gnat