2009-04-18 40 views
2

我有一些基本的类与克隆方法:单位在C#中测试的克隆方法与起订量

public class SimpleClass 
{ 
    public int ValueA { get; set; } 

    public string ValueB { get; set; } 

    public ulong ValueC { get; set; } 

    public SimpleClass TypedClone() 
    { 
     var item = new SimpleClass 
     { 
      ValueA = this.ValueA, 
      ValueB = this.ValueB, 
      ValueC = this.ValueC 
     }; 

     return item; 
    } 
} 

我想一个单元测试,会告诉我,如果我加重视,但忘记将它添加到克隆方法。我的第一个尝试是使用Moq和它的VerifyGet方法来确保每个属性都被访问。

public void GenericCloneTest() 
    { 
     var mock = new Mock<SimpleClass>(); 
     var c = mock.Object.GenericClone(); 
     var properties = typeof(SimpleClass).GetProperties(); 

     foreach (var property in properties) 
     { 
      var expression = Expression.Property(
       Expression.Parameter(typeof(SimpleClass), "c"), 
       property); 

      var type = Expression.GetFuncType(typeof (SimpleClass), 
       property.PropertyType); 

      var actionExpression = Expression.Lambda(type, expression, 
       Expression.Parameter(typeof(SimpleClass), "c")); 

      mock.VerifyGet<object> 
       ((Expression<Func<SimpleClass,object>>)actionExpression); 
     } 
    } 

这并不工作,因为VerifyGet方法需要知道属性访问的返回类型,我想不出任何方式在运行时将其插入(你会发现我的跛脚企图使用撞击和燃烧的“物体”)。

我甚至不确定使用Moq是一个好主意,它只是我的第一个。

更新:由于没有快速简单的通用方法来测试克隆方法,我决定为每个类编写特定于类型的测试。这仍然让我知道何时添加属性的问题。我决定把它添加到我的克隆单元测试中:

 var signature = typeof (Connection) 
      .GetProperties() 
      .Select(p => p.Name) 
      .Aggregate(
       new StringBuilder(), 
       (builder, name) => 
        builder.Append(name)).ToString(); 

     Assert.AreEqual(
      "DataSessionStateDataTechnologyBytesReceivedBytesSentDuration", 
      signature); 

如果我添加属性,则测试将失败。当签名匹配失败时,它仍然依赖于我有足够的责任来解决测试的其余部分。

回答

1

确保您获得所有字段的最简单方法之一是简单地使用MemberwiseClone()方法。这将自动将所有类字段复制到新实例。

+0

谢谢保罗!我一直认为必须有这样的.NET内置的东西,但还没有找到。这在我想做出快速浅拷贝的任何地方都很有用。 – MichaC 2009-04-18 02:37:01

2

你不想在这里使用Moq,你只需要使用一些反射。基本上写一个测试,创建一个对象的实例,设置每个属性,克隆它,然后确保每个属性在克隆上相同。

就像Paul说的那样,检查出MemberwiseClone(),它基本上是为你做的,或者至少实现ICloneable,这是一个标准的做法。 (MemberwiseClone()只做一个浅拷贝,这就是为什么你可能需要实现ICloneable)。然后你甚至可以编写一个测试,通过你的程序集查看所有实现ICloneable并测试它的东西。

+0

我开始只用反射来思考它,但最难的部分就是“设置每个属性”的步骤。我必须将每个属性设置为默认值以外的其他值来验证克隆方法,但是我拥有包含任意数量类型的属性集合。我必须编写知道如何更改和比较可能遇到的任何类型的代码。问题是,这是否比为每种类型编写独特的克隆测试更有效。 – MichaC 2009-04-18 02:48:48