2011-08-22 90 views
4

我們使用支持字段進行了大量關於我們的域對象的屬性,例如:自動測試屬性getter/setter方法

protected string _firstname; 

public virtual string Firstname 
{ 
    get { return _firstname; } 
    set { _firstname = value; } 
} 

我偶爾會做愚蠢的錯別字如下面的例子,並希望寫驗證所有這些屬性的單個測試,而不是手動爲每個對象進行測試。

public virtual string Firstname 
{ 
    get { return _firstname; } 
    set { _firstname = Firstname; } 
} 

難道是容易寫或不圖書館已經存在測試這些備份領域獲得/設置是否正確?這將僅在具有setter和(可能),使用駱駝情況相匹配的屬性名稱的支持字段屬性運行下劃線

+0

你檢查過pex和痣嗎? - http://research.microsoft.com/en-us/projects/pex/ – luketorjussen

+0

@Luke我曾與PEX玩過,但還沒有時間徹底使用它 –

+0

不會間接測試它們的測試嗎?屬性作爲其執行的一部分,捕捉這些錯誤?你真的需要更多的測試嗎? – Gishu

回答

5

另一種解決方案將是使用自動屬性來消除此問題:

public virtual string FirstName { get; set; } 

UPDATE (見評論,似乎需要支持領域): 另一種可能性是生成pocos。簡單的T4模板「Person.tt」

<#@ template language="C#" #> 
<# var pocos = new [] { 
    Tuple.Create("FirstName", "string"), 
    Tuple.Create("LastName", "string"), 
    Tuple.Create("Age", "int")}; #> 
public partial class Person { 
    <# foreach(var t in pocos) {#> 

    protected <#= t.Item2#> _<#= t.Item1.ToLowerInvariant()#>; 
    public virtual <#= t.Item2#> <#= t.Item1#> 
    { 
     get { return _<#= t.Item1.ToLowerInvariant()#>; } 
     set { _<#= t.Item1.ToLowerInvariant()#> = value; } 
    } 
    <#}#> 
} 

現在,當然這可能帶給人們的許多問題,因爲它解決了,但它可能是值得使用望着......也許:)

+0

我的問題最初沒有,但是特殊的後臺字段受到保護 –

+0

@Chris如果你想阻止編輯外面你可以讓setter受到保護。我真的不明白爲什麼你需要一個受保護的支持字段到公共虛擬屬性。你試圖通過保護它來實現什麼? – alun

+0

對於NHibernate(闡述..)他們不一定需要保護,但是當編譯器生成它們時,自動設置器不一定會匹配屬性名稱 –

2

除了汽車屬性我想用反射來測試我的模型..。

只要寫,得到您的類的所有屬性的通用方法,然後使用方法類似這樣:

/ get value of property: public double Number 
double value = (double)numberPropertyInfo.GetValue(calcInstance, null); 

[C#] 
// set value of property: public double Number 
numberPropertyInfo.SetValue(calcInstance, 10.0, null); 

對於示例:

void Main() 
{ 
     const int testValue=5; 
    var test = (Test)Activator.CreateInstance(typeof(Test)); 
    PropertyInfo valuePropertyInfo = typeof(Test).GetProperty("Value"); 
    valuePropertyInfo.SetValue(test, testValue, null); 
    int value = (int)valuePropertyInfo.GetValue(test, null); 
    Console.Write(value); //Assert here instead 

} 
public class Test 
{ 
private int _value; 
public int Value {get {return _value;} set{_value=Value;}} 
} 

以上函數的輸出爲0而不是預期的5。在這裏斷言會拋出一個錯誤。

您對這種方法有什麼看法。

1

Gallio/MbUnit有一個contract verifier這正是你正在尋找。的AccessContract的典型用法如下:

public class Foo // Dummy reference type. 
{ 
    private readonly int value; 
    public int Value { get { return value; } } 

    public Foo (int value) 
    { 
    this.value = value; 
    } 
} 

public class Bar 
{ 
    private Foo foo; 

    public Bar(string unusedParameter) { } 

    public Foo Foo // A complex property to be tested! 
    { 
    get { return foo; } 
    set 
    { 
     if (value == null) 
     throw new ArgumentNullException("value"); 
     if (value.Value < 0) 
     throw new ArgumentOutOfRangeException(); 
     if (value.Value == 666) 
     throw new ArgumentException("Inferno value strictly forbidden."); 

     foo = value; 
    } 
    } 
} 

和使用AccessorContract運行對房地產各種測試的測試夾具。

[TestFixture] 
public class BarTest 
{ 
    [VerifyContract] 
    public readonly IContract AccessorTests = new AccessorContract<Bar, Foo> 
    { 
     Getter = target => target.Foo, 
     Setter = (target, value) => target.Foo = value, 
     ValidValues = { new Foo(123), new Foo(456), new Foo(789) }, 
     AcceptNullValue = false, 
     DefaultInstance =() => new Bar("Hello"), 
     InvalidValues = 
     { 
      { typeof(ArgumentOutOfRangeException), new Foo(-123), new Foo(-456) }, 
      { typeof(ArgumentException), new Foo(666) } 
     } 
    }; 
} 

合同驗證生成以下的單元測試:

enter image description here

看一看的MbUnit test project更多應用實例。