比较两个相似物体的最佳方法是什么?
给定FlintlockDTO
和Flintlock
:
public class FlintlockDTO
{
public string GName { get; set; }
public string SharedPropertyName { get; set; }
...
}
和
public class Flintlock
{
public Flintlock(FlintlockDTO inflator)
{
this.GoodName = inflator.GName;
this.SharedPropertyName = inflator.SharedPropertyName;
...
}
public string GoodName { get; private set; }
public string SharedPropertyName { get; private set; }
...
}
如果两个类共享N个属性(例如SharedPropertyName
),但M属性相同,但名称不同(例如GoodName
\ GName
。)
fluentassert之类的工具差不多这样做,如果属性名称匹配,根据我的理解,这样可行:
flintlockDto.ShouldBeEquivalentTo(flintlock);
有没有办法在fluentassert或任何其他工具中巧妙地做到这一点?
理想地,
flintlockDto.IsTheSameAs(flintlock).WhenMapping("GName","GoodName");
答案 0 :(得分:2)
当我想要比较特定属性时,我有时会使用的一种策略是利用匿名类型,如下所示:
Assert.AreEqual(
new{flintlockDto.GoodName, flintlockDto.SharedPropertyName},
new{GoodName = flintlock.GName, flintlock.SharedPropertyName});
这并不依赖于任何特定的测试框架。它利用自动生成的Equals()
方法用于匿名类型,并且在失败的情况下,自动生成的ToString()
方法可以让您完整地描述两个对象的外观,这使得弄清楚出了什么问题。
您可能还想查看Mark Seemann的Likeness类型:
如何在不引入平等污染的情况下解决这个难题? AutoFixture以通用Likeness类的形式提供一个选项。此类提供从TSource到TDestination的基于约定的特定于测试的相等映射,并覆盖Equals方法。
...可以自定义比较以覆盖某些属性的行为......
答案 1 :(得分:2)
我决定详细说明StriplingWarrior提到的Likeness。它以nuget package提供。
以下是一个例子:
using NUnit.Framework;
using Ploeh.SemanticComparison;
using Ploeh.SemanticComparison.Fluent;
namespace Tests
{
[TestFixture]
class Tests2
{
[Test]
public void ObjectsShuldEqual()
{
var flintlockDto = new FlintlockDTO()
{
GName = "name",
AdditionalProperty = "whatever",
SharedPropertyName = "prop name"
};
var flintlock = new Flintlock(flintlockDto);
Likeness<Flintlock, FlintlockDTO> flintFlockDtoLikeness = flintlock
.AsSource().OfLikeness<FlintlockDTO>()
.With(dto => dto.GName).EqualsWhen((flintlock1, dto) => flintlock1.GoodName == dto.GName) // you can write an extension method to encapsulate it
.Without(dto => dto.AdditionalProperty);
// assert
flintFlockDtoLikeness.ShouldEqual(flintlockDto);
}
}
public class FlintlockDTO
{
public string GName { get; set; }
public string SharedPropertyName { get; set; }
public string AdditionalProperty { get; set; }
}
public class Flintlock
{
public Flintlock(FlintlockDTO inflator)
{
this.GoodName = inflator.GName;
this.SharedPropertyName = inflator.SharedPropertyName;
}
public string GoodName { get; private set; }
public string SharedPropertyName { get; private set; }
}
}
如你所见:
答案 2 :(得分:1)
您可以在测试项目中编写扩展类/方法并获得所需的结果,并且不会使用不必要的逻辑污染生产代码库。
static class Extensions
{
public static bool IsEqualTo(this FlintlockDTO expected, Flintlock actual)
{
return expected.GName == actual.GoodName && expected.SharedPropertyName == actual.SharedPropertyName;
}
}
在你的测试中,你将能够运行它:
Assert.IsTrue(expected.IsEqualTo(actual));
并且测试逻辑将无法在您的生产代码库中使用。
答案 3 :(得分:0)
让FlintlockDTO
实施IEquatable<Flintlock>
如下所示:
public override Equals(Flintlock other)
{
return GName == other.GoodName; // modify as necessary (case, culture, etc.)
}
(并且不要忘记覆盖并正确实施GetHashCode
。)
然后,您可以检查是否
flintlockDto.Equals(flintlock)
在您选择的单元测试框架中。