代码之家  ›  专栏  ›  技术社区  ›  Eddie Deyo

使用Moq,如何验证对象的所有属性都已复制?

  •  4
  • Eddie Deyo  · 技术社区  · 16 年前

    我有一个带有CopyFrom()方法的接口,它从另一个对象复制所有属性。我有一个测试,它执行几个VerifyGet()调用,以确保从传递的对象中检索每个属性,例如:

    Thing target = new Thing();
    IThing source = new Mock<IThing>();
    
    target.CopyFrom(source.Object);
    source.VerifyGet(t => t.Foo);
    source.VerifyGet(t => t.Bar);
    

    我想要一种方法来迭代 IThing 但是,请验证每个属性都是自动复制的,因此如果有人添加了属性但忘记复制它,则测试将失败。有没有办法通过Moq做到这一点?我试过了;

    foreach (var prop in typeof(IThing).GetProperties())
    {
        source.VerifyGet(t => prop.Invoke(t, null));
    }
    

    但由于lambda不表示属性访问器,因此它不起作用。我想应该有办法通过 Expression 同学们,但我对LINQ还不够熟悉,不知道应该放些什么。

    2 回复  |  直到 16 年前
        1
  •  4
  •   Mark Seemann    16 年前

    我不认为Moq有这种可能,但首先你需要质疑你的测试是否相关。你真的想在这里测试什么?

    CopyFrom方法重要吗 读取 有什么财产吗?当然可以 阅读 所有的属性都没有写入新实例,所以这样一个基于交互的测试并不能证明什么。

    我猜您真正想测试的是目标的属性等于源的属性?

    假设i thing上的属性是可写的,则可以使用SetupAllProperties方法创建一个具有所有属性集的存根:

    var sourceStub = new Mock<IThing>();
    sourceStub.SetupAllProperties();
    sourceStub.Object.Bar = "Bar";
    sourceStub.Object.Foo = "Foo";
    

    然后需要将目标与源进行比较,以查看所有属性是否匹配。可以通过在包装实际目标的类中实现特定于测试的Equals方法来实现。

    如果你觉得那工作太多,你可能想退房 AutoFixture 的类,该类为您提供通用的特定于测试的相等性比较。这样您就可以继续这样的测试:

    var expectedResult = new Likeness<IThing>(sourceStub.Object);
    
    target.CopyFrom(sourceStub.Object);
    
    Assert.AreEqual(expectedResult, target);
    

    Likeness使用反射简单地循环包装对象中的所有公共属性,并查看比较对象是否具有这些属性的相同值。

        2
  •  1
  •   Michael    13 年前
    /// <summary>
    /// Verifies that a property was read on the mock
    /// </summary>
    public static void VerifyGet<T>(this Mock<T> mockedObject, string propertyName) where T : class
    {
        var property = typeof(T).GetProperty(propertyName);
        if (property == null)
            throw new ArgumentException(string.Format("No property by the name '{0}' was found on '{1}'.", propertyName, typeof(T).Name));
    
        // getPropFuncExpression = obj => obj.propertyName;        
        var parameterExpression = Expression.Parameter(typeof(T), typeof(T).Name);
        var propertyExpression = Expression.Property(parameterExpression, property);
        var getPropFuncExpression = Expression.Lambda(propertyExpression, parameterExpression);
    
        var verifyGet = mockedObject.GetType().GetMethods().Single(m => m.Name == "VerifyGet" && m.GetParameters().Length == 1);
        verifyGet.MakeGenericMethod(property.PropertyType).Invoke(mockedObject, new object[] { getPropFuncExpression });
    }
    

    您可以添加上述扩展方法,以便只调用:

    foreach (var prop in typeof(IThing).GetProperties())
    {
        source.VerifyGet(prop.Name);
    }
    
    推荐文章