2016-08-22 3 views
2


私はコードこのExpressionエバリュエータークラスのプライベートメソッドの単体テストを記述してもよろしいですか?

public interface IInterpreter 
{ 
    decimal Evaluate(string expression); 
} 

public class Interpreter : IInterpreter 
{ 
    public decimal Evaluate(string expression) 
    { 
     if (String.IsNullOrWhiteSpace(expression)) 
      throw new ArgumentException("Parameter " + nameof(expression) + " cannot be empty"); 

     var rpnExpression = ConvertToReversePolishNotation(expression); 
     return EvaluateReversePolishExpression(rpnExpression); 
    } 
... 
} 

このクラスは、 "+ 5 * 6" のような式を評価したりします "(3-5)*(2 + 2)+5"
を以下のカントー今私が欲しいいますユニットテストを書く。ここで公開されている唯一の関数はEvaluateであり、すべての勧告によれば、このメソッドのみをテストする必要があります。
問題は、私は両方のConvertToReversePolishNotation(expression)EvaluateReversePolishExpression(rpnExpression)関数が単体テストでカバーされなければならないという強い感情を持っています... Evaluateメソッドのためにいくつかの単体テストが失敗する場合は、バグがどこにあるのかを指摘しません(ConvertToRPNExpressionメソッドEvaluateReversePolishExpressionファンクション)。

質問があります - この場合、プライベート関数の単体テストを書くのは大丈夫ですか?

答えて

5

リファクタリング別々のクラスにConvertToReversePolishNotation方法。その関心事は変換です。

インタープリタの懸念は評価することです。あなたが変換の出力を模倣している場合は、公開のEvaluateメソッドを使ってテストするのは簡単です。

+0

応答に感謝します。あなたが正しいと思われます... – Disappointed

+0

@Disappointedでは、クラスが複雑になるかどうかを検証するために、「単一の責任原則」を使用することができます。通常、あなたのユニットテストの問題は良い指標です – Aphelion

1

はい、問題ありません。

Evaluateのユニットテストでは、ConvertToReversePolishNotationEvaluateReversePolishExpressionが実際に実装されています。

Aphelionは自分自身の責任のためにクラスを分けることができますが、ConvertToReversePolishNotationの場合にのみ、EvaluateReversePolishExpressionのプライベートメソッドを作成する必要はありません。これはそれが既に行われているためです。 evaluateを呼び出す前に、呼び出し元はConvertToReversePolishNotationのクラスを呼び出し、それをパラメータとして渡す必要があります。

privateメソッドのユニットテストではないと心配している場合は、internalメソッドを使用できます。

トピック:この機能を拡張および拡大する方法も念頭に置く必要があります。通訳者がdecimal以外のデータ型を返すことを希望する場合はどうなりますか?ジェネリックも最大化したいとは思わないでしょうか?

public decimal Evaluate(string expression) 
{ 
    if (String.IsNullOrWhiteSpace(expression)) 
     throw new ArgumentException("Parameter " + nameof(expression) + " cannot be empty"); 

    return EvaluateReversePolishExpression(expression); 
} 
+1

私はあなたが@Aphelionに同意すると理解していますが、彼の短い答えはYesです。 – Disappointed

+0

@Disappointed私はあなたがそれを分けることができると私は同意しません。いいえ、私的な機能の単体テストを書くのは大丈夫ではないということです。基本的にあなたの大胆な質問でした。ときどき無視するのは本当に必然です。書籍/著者のうちの1人が私的機能の単体テストを書くのが悪いと言っているからといって、それは難しいルールではありません。 –

+0

さて、彼の質問は「この場合」であり、難しいルールではありません:) – Aphelion

2

私は3つのクラスを作成します.1つは検証の責任者、1つは変換のためのもの、もう1つは評価のためのクラスです。

実際の実装から切り離すコンストラクタ依存性注入を使用するよりも。 これを手動でインスタンス化するか、コンテナを委譲してコンテナを初期化してください。インタプリタに変更を加えることなく動作を変更することができます。

このルートを使用すると、依存関係の呼び出し順序を簡単にテストできるため、インタープリターの動作をテストできます。 妥当性検査、変換、評価と同様です。

これとは別に、単一のクラスの各実装をテストできます。

クラスはまた、検証する責任があり、外部クラスを呼び出して操作を実行するので、イベントの流れを記述する責任があるため、単一責任の原則を制動しています。

また、変換と評価の実装クラスを密接に結合すると、Open Closeの原則が破られます。

+1

妥当性検査は単純なガードです。なぜ入力ガードを別のクラスに移動させるのですか? – Aphelion

関連する問題