2

我有一些带有克隆方法的基本类:

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;
    }
}

我想要一个单元测试,它会告诉我是否添加了 ValueD,但忘记将其添加到 Clone 方法中。我的第一次尝试是使用 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 方法需要知道 Property 访问器的返回类型,而且我想不出任何在运行时插入它的方法(你会注意到我尝试使用崩溃的“对象”的蹩脚尝试)烧毁)。

我什至不确定使用起订量是个好主意,这只是我的第一个。

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

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

      Assert.AreEqual(
           "DataSessionStateDataTechnologyBytesReceivedBytesSentDuration",
           signature);

如果我添加一个属性,测试将失败。当签名匹配失败时,它仍然取决于我是否有足够的责任来修复测试的其余部分。

4

2 回答 2

3

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

于 2009-04-18T01:35:04.063 回答
2

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

就像保罗说的那样,请查看基本上为您执行此操作的 MemberwiseClone(),或者至少实现 ICloneable,这是如何执行此操作的标准做法。(MemberwiseClone() 只做一个浅拷贝,这就是你可能需要实现 ICloneable 的原因)。然后,您甚至可以编写一个测试,通过您的程序集查找实现 ICloneable 的所有内容并对其进行测试。

于 2009-04-18T02:16:31.777 回答