2011-08-22 101 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更多应用实例。