【问题标题】:More informative comparison of objects in C#C# 中对象的更多信息比较
【发布时间】:2017-12-19 23:28:03
【问题描述】:

在我的 C# 测试中,我经常想比较两个相同类型的对象(通常是预期对象与实际对象),但我想允许一些灵活性。例如,可能有一些我知道不能相等的时间戳字段,或者在比较对象时我只想忽略一些字段。

最重要的是,我想提供一条信息性消息,描述两个对象属性值的不同之处,以便我可以快速确定问题所在。例如,一条消息说“源属性名称值 Fred 与目标属性名称值 Freda 不匹配”。

标准的 Equals 和 Comparer 方法似乎只返回整数或布尔值,它们没有为我提供足够的信息。目前,我的对象比较方法返回一个自定义类型,它有两个字段(一个布尔值和一个消息),但我的想法是必须有一个更标准的方法来做到这一点。这些天来,也许元组可能是要走的路,但我欢迎提出建议。

【问题讨论】:

  • 我在发布之前通读了引用的问题及其答案,但它并没有真正解决完全相同的问题。我更关心性能,而不是获取有关比较失败的位置和方式的有用信息。因此,我需要更多信息才能返回,而不仅仅是布尔值或 int。
  • 我认为您的问题过于宽泛,无法回答。或许您可以提出一些您假设的返回类型的示例用法?
  • 我猜你可以使用反射,或者只是滚动你自己的比较例程

标签: c# testing compare


【解决方案1】:

“比较”可能不是您想要做的事情。在这种情况下,这个词已经具有共同的含义。我们比较对象是否相等,它返回一个boolean——它们相等或不相等。或者我们比较它们,看看哪个更大。这将返回一个int,它可以指示一个或另一个更大,或者它们相等。这在对对象进行排序时很有帮助。

您要做的是确定对象之间的具体差异。我不会尝试编写一些通用的东西来处理不同类型的对象,除非你想让它们变得非常简单。当您进入返回其他复杂对象或集合或复杂对象集合的属性时,这变得非常复杂。与编写一个比较您要比较的特定类型的方法相比,这并非不可能,只是很少值得付出努力。

这里有一些接口和类可以使任务更容易和更一致。但老实说,很难说该怎么做。同样,如果您要处理嵌套的复杂属性,它会变得复杂。如果两个属性都包含其他对象的列表,并且这些列表中的所有项目都相同,除了每一侧具有不同属性的项目之外,会发生什么情况。或者如果它们都不同呢?在那种情况下,您将如何描述父对象的“不平等”?知道它们相等或不相等可能很有用,但以某种方式描述差异就不那么有用了。

public interface IInstanceComparer<T>
{
    IEnumerable<PropertyDifference> GetDifferences(T left, T right);
}

public abstract class InstanceComparer<T> : IInstanceComparer<T>
{
    public IEnumerable<PropertyDifference> GetDifferences(T left, T right)
    {
        var result = new List<PropertyDifference>();
        PopulateDifferences(left, right, result);
        return result;
    }

    public abstract void PopulateDifferences(T left, T right, 
       List<PropertyDifference> differences);
}

public class PropertyDifference
{
    public PropertyDifference(string propertyName, string leftValue, 
        string rightValue)
    {
        PropertyName = propertyName;
        LeftValue = leftValue;
        RightValue = rightValue;
    }
    public string PropertyName { get; }
    public string LeftValue { get; }
    public string RightValue { get; }
}

public class Animal
{
    public string Name { get; }
    public int NumberOfLimbs { get; }
    public DateTime Created { get; }
}

public class AnimalDifferenceComparer : InstanceComparer<Animal>
{
    public override void PopulateDifferences(Animal left, Animal right, 
        List<PropertyDifference> differences)
    {
       if(left.Name != right.Name) 
           differences.Add(new PropertyDifference("Name", left.Name, right.Name));
       if(left.NumberOfLimbs!=right.NumberOfLimbs) 
           differences.Add(new PropertyDifference("NumberOfLimbs", 
               left.NumberOfLimbs.ToString(), 
               right.NumberOfLimbs.ToString()));
    }
}

【讨论】:

  • 这是在精神上与我目前所做的最接近的答案。我必须承认,我希望有人能描述一种我不知道的 C# 或标准库中已经存在的“现成”方法,但也许希望太高了!
【解决方案2】:

您可以使用扩展方法来执行此操作。例如:

public static Extensions
{
    public static void CompareWithExpected(this <type> value, <type> expected)
    {
        Assert.AreEqual(expected.Property1, value.Property1, "Property1 did not match expected";
        Assert.AreEqual(expected.Property2, value.Property2, "Property2 did not match expected";
    }
}

那么可以这样使用:

public void TestMethod()
{
    // Arrange
    ...

    // Act
    ...

    // Assert
    value.CompareWithExpected(expected);
}

您可以拥有任意数量的这些扩展方法,让您可以灵活地仅检查某些值等。

这也意味着您不需要使用本质上是测试代码的内容来污染您的类型。

【讨论】:

    猜你喜欢
    • 2023-03-11
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 2013-03-14
    • 2023-03-11
    相关资源
    最近更新 更多