比较单元测试中的相似对象
本文关键字:相似 对象 单元测试 比较 | 更新日期: 2023-09-27 18:03:20
比较两个相似对象的最佳方法是什么?
给定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
)
flintlockDto.ShouldBeEquivalentTo(flintlock);
是否有办法在fluentassert或任何其他工具中巧妙地做到这一点?
在理想的情况下,
flintlockDto.IsTheSameAs(flintlock).WhenMapping("GName","GoodName");
我决定详细说明一下StriplingWarrior提到的相似性。它是一个nuget包。
下面是一个例子:
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; }
}
}
如你所见:
- 它对同名的属性执行自动比较
- 你可以指定不同名称的属性是否应该匹配(这个实际上是相当丑陋的开箱,但你可以写一个扩展方法来封装它)
- 你可以指定一个属性是否不应该被比较
当我想将特定的属性放在一起比较时,我有时使用的一种策略是利用匿名类型,如下所示:
Assert.AreEqual(
new{flintlockDto.GoodName, flintlockDto.SharedPropertyName},
new{GoodName = flintlock.GName, flintlock.SharedPropertyName});
这并不依赖于任何特定的测试框架。它利用匿名类型的自动生成的Equals()
方法,在失败的情况下,自动生成的ToString()
方法为您提供了两个对象的完整描述,这使您很容易找出哪里出了问题。
你可能还想看看Mark Seemann的肖像类型:
我们如何在不引入平等污染的情况下解决这个难题?AutoFixture以通用的Likeness类的形式提供了一种选择。该类提供了从TSource到TDestination的基于约定的测试特定的相等映射,并覆盖Equals方法。
…可以自定义比较来覆盖某些属性的行为…
您可以在您的测试项目中编写一个扩展类/方法并获得您想要的结果,并且您不会用不必要的逻辑污染您的生产代码库。
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));
和测试逻辑在您的生产代码库中不可用。
让FlintlockDTO
实现IEquatable<Flintlock>
可能是好的:
public override Equals(Flintlock other)
{
return GName == other.GoodName; // modify as necessary (case, culture, etc.)
}
(不要忘记重写并正确实现GetHashCode
)
然后,你可以检查是否
flintlockDto.Equals(flintlock)