2016-05-12 32 views
3

私はthisを見ましたが、本当に良い答えはありませんでした。クラスの動作をテストする必要がある場合もありますが、プライベートデータの一部を検査する必要があることを実際に主張するには、ユニットテスト(java):データをユニットテストに公開するpublicメソッドを記述する必要がありますか?

例:ファイルから読み込んだランダムな単語を返すクラスを作成しています。だから私は、このようなクラス設計された:私はwordsListを公開したくない

public class WordsDatabase { 
    private List<String> wordsList = new ArrayList<String>(); 

    public WordsDatabase() { 
     fillWordsListFromFile(); 
    } 

    private void fillWordsListFromFile() {...} 

    public String getRandomWord() {...} 
} 

を、今どのようにすべきIユニットテストgetRandomWord()は本当に私の辞書テキストファイルから私にランダムな単語を取得している場合はどうなりますか?

私がテストできるのは、単語を返すかどうかだけですが、単語がファイルからランダムに選択されているかどうかはわかりません。

私は一様分布のカイ二乗検定を行うことができるかどうかをテストするために、少なくとも私はwordsList.size()を何とか知っていなければなりません。

はおそらく、私があまりにも深いテストを実行するだけで喜ん...

EDIT:回答を

おかげで、チップを得ました。クラスがテストするのが難しいときは、そのデザインに何か問題があるためかもしれません。

+0

正確には重複していませんが、この質問は非常に近いです:http://stackoverflow.com/questions/34571/how-to-test-a-class-that-has-private-methods-fields-or -inner-classes?rq = 1 –

+0

私はそれを見ましたが、私はReflectionsを本当に混乱させるべきでしょうか? – caiohamamura

+1

これはプログラミング理論/ベストプラクティスのためのスタックエクスチェンジサイトであるhttp://programmers.stackexchange.com/に属しています。 'Stack Overflow'(このサイト)は特定のプログラミング/コードに関する質問です。あなたの質問はユニットテスト理論/ベストプラクティス/アプローチに関するものです。 – mmcrae

答えて

2

「getRandomWord()が実際に私の辞書テキストファイルからランダムな単語を取得している場合、どのようにユニットテストすればよいですか?」

これはモックの完璧な使用例のようです。& dependency injectionあなたのユニットテストで

  • は、この更新後
  • を呼び出したときに、特定のデータを返します/非常に限られたコンテンツを持っている別の模擬辞書に渡す

    1. アップデートので、この辞書は、構築時に渡されるクラス、 getRandomWordのユニットテストでは、あなたの模擬ワードリストの期待されるデータが使用されたことを単に検証しています。

    スプリングのようなフレームワークを使用している場合は、依存性注入用に設計されています。 This other answerには、これを解決するためのスプリングの使用に関するいくつかの良い点があります。

  • +1

    これは興味深い解決策ですので、クラスは1つの辞書に縛られません。実際にはこれはさらに優れた設計です。なぜなら、それが実際にクラスではなく、ほとんどのオブジェクトであったからです。 – caiohamamura

    +0

    クラスを2つに分割することはお勧めできません.1つは読んで、もう1つはリストからランダムな単語を取得することです? – LukeW

    +0

    @LukeW依存関係インジェクションを使用するためにこれをリファクタリングする方法はたくさんあります。これは可能な考え方です。別の依存関係として 'RandomNumberProvider'を抽出する方法もあります。このための「正しい」内訳は、周囲のコンテキストに完全に依存します。つまり、このクラスはどのように適合しますか?再利用できるものは他に何がありますか?他の場所で何を再利用できるの?等 – Krease

    2

    パブリックメソッドのみをテストして、クラスが好きなように機能するかどうかを確認する必要があります。

    オブジェクトの内部状態をテストすることは、オブジェクトの内部表現が変更される可能性があるため、適切ではありませんが、メソッドの動作は同じになる可能性があります。

    変数/メソッドの可視性をクラスの単体テストに変更する必要はなく、このような問題を解決するためにヒントとして使用されることもあります。


    注:wordsListのサイズを知る必要がある場合。 wordsListの読み込み方法を確認する必要があります。あなたのコードからは、ファイルからデータが取り込まれているようです。したがって、テストで使用するファイルを定義します。このファイルの内容を知っていれば、wordsListのサイズの内部値を確認する必要はありません。

    +0

    ありがとう、テストコードで同じファイルを使用していましたが、ユニットテストを複雑にすることを恐れていました。静的なTEXTFILEPATHを公開して両方を同じにする必要があります。 – caiohamamura

    1

    本当に選択肢がない限り、JUnitテストでは反射を使用しないでください。プライベート変数が関係するテストを実行する場合は、注入または自動配線を使用する必要があります。

    は、注釈のこれらの種類を使用して考えてみて:あなたのケースでは

    1. @Inject
    2. @Autowire
    3. @Bean
    4. @Produce
    5. @value

    を、あなたのリストのために、@ Injectまたは@Autowireはあなたのvを注入するのに最も適した注釈ですariable。アプリケーションコンテキストを定義する必要があることを忘れないでください。 CDIをサポートする他の大きなプラフォームには、SpringまたはJ2EEだけを使用してください。

    さらに、ある理由でプライベートメソッドがある場合は、そのようにしてください。私は一般的には、単体テストを満たすためだけにメソッドをpublicにするのは悪い考えだと思います。

    1

    デザインを変更すると、クラスをより簡単にテストすることができます。あなた、例えば、あなたのWordsDatabaseにサービス/データアクセスオブジェクトを挿入でき、実際にいくつかのリソースからあなたのための単語を取得し、 mocakable /スワップ可能であるという利点があります。

    public class WordsDatabase { 
        private List<String> wordsList = new ArrayList<String>(); 
    
        public WordsDatabase(WordService wordService) { 
         wordsList.addAll(wordService.getWords()); 
        } 
    
        public String getRandomWord() { 
         // Interact with wordsList or wordService directly. 
        } 
    } 
    

    例のサービス・インターフェース:

    public interface WordService { 
        List<String> getWords(); 
    } 
    

    今、あなたのテストでは、あなたのいずれかを行うことができmock文字列の適切なListを返す、またはいくつかの他のコントロールの実装を提供WordServiceのインスタンス。

    クラスの依存関係を制御すると、この種の問題(ほとんど)がなくなります。詳細については、dependency injectionの例をご覧ください。

    関連する問題