2016-07-20 2 views
3

Result(以下を参照)を返す関数をユニットテストする必要があります。深く入れ子になった差別化された組合を比較するにはどうすればいいですか?

私の質問は:結果が数値的に期待値と等しいかどうかを簡単に確認する方法はありますか?

正確に一致するバージョンがあります。

type QuadraticResult = 
    | ComplexResult of Complex * Complex 
    | DoubleResult of float 
    | TwoResults of float * float 


type Result= 
    | QuadraticResult of QuadraticResult 
    | LinearResult of LinearFormulaSolver.Result 

/// Solves a x² + bx + c = 0 
let Compute (a,b,c) : Result = 



[<Fact>] 
member test.``the solution for x² = 0.0 is a double 0.0``()= 
    let result = Compute (1.0, 0.0, 0.0) 
    let expected = Result.QuadraticResult (DoubleResult 0.0) 

    // only exact match, I'd like to test if difference is below a certain threshold 
    Assert.Equal (result, expected) 

ここまでは私が使用している解決策です。 Andreysソリューションに基づいていますが、許可された距離、結果の順列および線形の場合に拡張されています。 :

let ComplexEquality distance (x : Complex) (y : Complex)= 
     let dx = x.Real - y.Real 
     let dy = x.Imaginary - y.Imaginary 
     abs (dx) < distance && abs(dy) < distance 


let QuadraticEquality distance x y = match (x,y) with 
         | (ComplexResult (a,b),ComplexResult(c,d)) -> (ComplexEquality distance a c && ComplexEquality distance b d) || (ComplexEquality distance a d && ComplexEquality distance b c) 
         | (DoubleResult a,DoubleResult b) -> abs (a - b) < distance 
         | (TwoResults (a,b),TwoResults(c,d)) -> (abs(a - c) < distance && (b - d) < distance) || (abs(a - d) < distance && (b - c) < distance) 
         | _ -> false 

let LinearEquality distance x y = match (x , y) with 
         | (SingleResult a, SingleResult b) -> abs (a-b) < distance 
         | (NoResults, NoResults) | (InfiniteResults, InfiniteResults) -> true 
         | _ -> false 


let ResultEquality distance x y = match (x,y) with 
         | (QuadraticResult a,QuadraticResult b) -> QuadraticEquality distance a b 
         | (LinearResult a,LinearResult b) -> LinearEquality distance a b 
         | _ -> false 

[<Fact>] 
member test.``the solution for x² = 0 is a double 0``()= 
    let result = QuadraticFormulaSolver.Compute (1.0, 0.0, 0.0) 
    let expected = Result.QuadraticResult (QuadraticFormulaSolver.DoubleResult 0.00001) 

    Assert.True(ResultEquality 0.001 result expected) 

答えて

1

私はあなただけのヘルパー関数を記述する必要があると思います。たとえば、次のように

open System.Numerics 


type QuadraticResult = 
    | ComplexResult of Complex * Complex 
    | DoubleResult of float 
    | TwoResults of float * float 

type Result= 
    | QuadraticResult of QuadraticResult 
    | LinearResult of int 

let QuadraticEquality x y = match (x,y) with 
          | (ComplexResult (a,b),ComplexResult(c,d)) -> (a.Equals c) && (b.Equals d) 
          | (DoubleResult a,DoubleResult b) -> a = b 
          | (TwoResults (a,b),TwoResults(c,d)) -> (a = b) && (c = d) 
          | _ -> false 

let ResultEquality x y = match (x,y) with 
         | (QuadraticResult a,QuadraticResult b) -> QuadraticEquality a b 
         | (LinearResult a,LinearResult b) -> a = b 
         | _ -> false 

そして、あなたの詳細な回答のため

Assert.IsTrue(ResultEquality result expected); 
+0

私の質問にはあなたのソリューションの拡張版が含まれています。 – Onur

6

私はあなたがこれを自動的に行う聞かせウォルド任意の「手品」があるとは思いません。そのfloat上のラッパーを書く

ネストされたすべてのfloat値については、既存のタイプ上で動作し、比較の特別な種類を行い、平等のテストを行うために

  1. 書き込みカスタム関数

  2. を:私はあなたの3つのオプションを持っていると思いますカスタム比較を実装し、識別された共用体内でこの型を使用します。

  3. カスタム等価性テストを実行するためのリフレクションベースの魔法を書き込みます。

これらのうち、(1)はおそらく最も簡単なオプションです - これはもう少しタイピングを意味しますがこのカスタム比較をプログラムのどこでも使用したい場合は、オプション(2)が面白いかもしれません。 finally(3)は、さまざまなネストされた型がたくさんある場合には理にかなっていますが、エラーが発生しやすいオプションでもあります。

私は(2)の最小限のデモを書いたが、私はまだ(1)は、おそらくより良いアプローチだと思う:

[<Struct; CustomComparison; CustomEquality>] 
type ApproxFloat(f:float) = 
    member x.Value = f 
    override x.GetHashCode() = f.GetHashCode() 
    override x.Equals(another) = 
    match another with 
    | :? ApproxFloat as y -> abs (x.Value - y.Value) <= 0.001 
    | _ -> false 
    interface System.IComparable with 
    member x.CompareTo(another) = 
     match another with 
     | :? ApproxFloat as y -> compare x.Value y.Value 
     | _ -> failwith "Cannot compare" 

type Complex = 
    | Complex of ApproxFloat * ApproxFloat 

type Result = 
    | Result of Complex 

Result(Complex(ApproxFloat(1.0), ApproxFloat(1.0))) = 
    Result(Complex(ApproxFloat(1.0001), ApproxFloat(1.0001))) 
+0

感謝を書きやすいテストインチ私は単なる単体テストのためにこれを必要とするので、私は自分のタイプを変更したくないでしょう(これはいつも "私の"タイプのbtwではありません)。深層に置かれていても、 'float'値に到達する簡単な方法はありますか?フロート値自体を比較することができました。 'Complex'の場合(これは.NETライブラリの一部なので、簡単に変更できません)、' areRoughlyEqual'関数がオプションになると思いますが、もう一度 'Complex'に行くための素早い方法が必要です値。 – Onur

関連する問題