2012-11-01 44 views
0

我的應用程序中有一個常量,它決定了程序某些其他部分的操作。我改變這個常數可以快速輕鬆地改變程序的運行。測試常量的所有可能值

在我的情況下,常數是bool,所以它可以有兩個值中的一個。

我想編寫一個測試,以確保我的代碼正常工作,無論常量是否設置爲true。

例如,說我的方法是這樣的:

public boolean IsEqual(float a, float b) { 
    var epsilon = 0.0001; 

    if (Constants.Exact) return (Math.Abs(a-b) < epsilon); 
    else return (Math.Floor(a) == Math.Floor(b)); 
} 

Constants看起來是這樣的:

public static class Constants { 
    /// <summary> 
    /// Determines whether an exact comparison should be made, or whether fractional parts should be disregarded. 
    /// </summary> 
    public const bool Exact = true; 
} 

而且測試方法是:

[TestMethod] 
public void TestEquality() { 
    var five = 5; 
    var three = 3; 

    Assert.True(Equals(five, three)); 
} 

解決方案我能想出與:

  • 編寫測試就好像常數不存在一樣,將常量設置爲true並運行測試,然後將其設置爲false並運行測試。不好的,因爲如果我有這樣的8個常量,我不想運行測試256次。
  • 不要讓它成爲一個常量。在測試方法內部,首先將常量設置爲true,斷言然後是false,再次斷言。然而,我首先使它保持不變的原因是它保證在運行時不會改變。

我想我真正想要的是一種使應用程序本身保持恆定的方法,但就測試項目而言,這並不是一個常量。

那麼,我該如何做出這樣的工作?

+1

我知道這不是你要求的,但使用==比較浮點數很少是一個好主意。你爲什麼想要啓用它? –

+1

你可以用一個'internal' setter來使它成爲靜態的,那麼你只需要確保你不要在該項目中(或者通過InternalsVisibleTo'暴露它的項目中)更改它。 –

+0

@BrianRasmussen編輯添加epsilon比較,但這只是一個簡單的例子。我實際上並沒有比較花車。 – Superbest

回答

3

創建函數的兩個重載,一個有附加exact參數和一個使用Exact不斷隱含

public bool IsEqual(float a, float b) 
{ 
    return IsEqual(a, b, Constants.Exact); 
} 

public bool IsEqual(float a, float b, bool exact) 
{ 
    if (exact) 
     return a == b; 
    else 
     return Math.Floor(a) == Math.Floor(b); 
} 

現在,您可以測試的excat任何值,而不依賴於預先定義的常量。


UPDATE使用IEquatable<float>(見註釋)

IEquatable<T>.Equals只有一個參數。因此,我認爲其他的值在這個例子中

public float Value { get; set; } 

#region IEquatable<float> Members 

public bool Equals(float other) 
{ 
    return Equals(other, Constants.Exact); 
} 

#endregion 

public bool Equals(float other, bool exact) 
{ 
    if (exact) 
     return Value == other; 
    else 
     return Math.Floor(Value) == Math.Floor(other); 
} 
+0

即使該方法被稱爲「Equals」並實現了「IEquatable .Equals」,也可以這樣做。有了超載,你只需要一個不實現接口的方法。我沒有看到任何問題。 –

+0

是的,我後來意識到它不影響繼承,所以我刪除了評論。 – Superbest

0

使用枚舉而不是常量。這樣你可以防止它被改變成意想不到的事情,但它是可以修改的,並且可以用更多的值來擴展。

+2

Enum變量可以設置爲枚舉定義以外的值;它只是支持類型的薄單板(通常是int)。例如,您可以執行'var x =(MyEnum)-1235412;'。 –

+0

如果您在C++中使用枚舉類11 –

+0

我認爲它比改變常量要好。 – Lojko

1

你可以在內部創建的常量和通過屬性代表它定義爲財產Value,所以你說

private const bool _exact = false; 

    public bool Exact 
    { 
    get { return _exact }; 
    set { throw new Exception("Don't set this, you crazy donkey") }; 
    } 

然後測試你能創建一個繼承自常量類的類,但會覆蓋Exact屬性。只要你在父類中使用它的公有名稱來調用它,那麼你應該能夠改變測試中的值,並在常規實現中保持它的不變。

編輯:事實上,如果你的常量都是在一個類中定義的,那麼最好的方法是簡單地從該類中提取接口,然後你可以在測試時切換實現(或者任何其他的,重新使用某種類型的DI框架),或者簡單地使用一個模擬框架來模擬出給定測試所需的任何部分。

+0

因此,如果在我的測試項目中,我聲明一個工作setter的'Exact'覆蓋,這不會做任何事情,因爲'IsEqual'方法顯式引用'Constants'類中的'Exact',而不是在測試課上? – Superbest

+0

是的,當然你是對的,你需要在Constants類中做到這一點,而不是使用屬性。 – glenatron