如何在单元测试中测试两个对象的相等性?

4
我有一个项目,其中我从DTO(数据传输对象)接收对象并将它们转换为视图模型。为了进行此转换,我决定创建一些自定义转换器,以便从DTO属性转换为视图模型时进行一些计算。在所有这些准备就绪,并且转换正在工作之后,我想添加一些单元测试到转换中,以使其更加稳定(我知道这不符合TDD的要求,但这是我能做到的)。问题出现在当我想要测试验证两个视图模型的相等性时。
Assert.AreEqual(expected, actual);

因为没有一个View-Model定义了Equals方法,并且它们永远不会作为引用相等。以下是我想到和发现可以比较这些对象的一些方法:
  1. 定义Equals方法。但我不知道是否值得为测试目的而定义。如果我定义了,最好还要定义GetHashCode方法,因此我认为这种解决方案并不是最好的。

  2. 另一种可能性是在测试项目中实现IEqualityComparer<T>,以将比较逻辑与主转换项目隔离开来,或者将其提取到第三个项目中,以便将来的转换模块可以使用它(如果需要)。这个实现看起来很好,但我不知道是否值得添加另一个具有许多类的项目,这些类也应该进行测试。

  3. 我在一个Stack Overflow问题上发现的第三种方法看起来很有趣,就是序列化这两个对象并比较字符串。问题是我不知道这是否是编程的好习惯。

这些方法中哪一种是比较对象的最佳方式?我是否忽略了一些更有效的方法?
注:View-Models是复杂对象,我不能改变转换到其他技术的方式。

看起来你已经列出了优缺点 - 我不会相信序列化,除非它们是相同的类型 - 有很多原因,为什么两个具有相同属性的类型可能会序列化不同。 - D Stanley
@DStanley 看起来它们始终是相同的类型,但如果我使用泛型类型参数创建一个方法,就像从IEqualityComparer中的Equals一样,该方法接收两个对象并且不仅进行简单比较,而是将它们序列化并返回它们的字符串比较?这种方式足够稳定吗? - meJustAndrew
@DStanley,我看到您已经投票关闭此问题,因为它过于广泛,但我已经阅读了帮助中心中关于何谓过于广泛的说明,我认为这个问题并不适用于该部分,因为它的答案不需要编写整本书或非常长的答案。请考虑许多其他编程问题可能有多个答案,这些答案都很好,但没有一个使它们变得“过于广泛”。谢谢! - meJustAndrew
实际上,我(和其他4个人)投票将其关闭为基于观点的问题,因为您提出的所有解决方案在技术上都是可行的,因此“最佳”通常是一个观点问题。无论如何,您已经接受了一个答案,所以“没有伤害,没有过失”。 - D Stanley
@DStanley 我理解这一点,但如果有其他建议,我会非常欢迎,并且我认为保持这个问题开放不会有任何伤害。我仍然尊重您的决定! - meJustAndrew
2个回答

3

你的第二种方法比其他两种要好得多,因为它将测试特定的代码与单元测试放在一起,而且它还可以让您更改什么样的视图模型被认为是相等的。

把相等比较器移到一个单独的项目中几乎不值得,如果您打算共享相等比较逻辑,那么您可能会将其放入您的对象中。另一方面,如果它只是为了测试而设计的,那么应该将其与测试保持在一起(即使用第一种方法)。

基于序列化的方法过于脆弱,因为它依赖于一个无关的功能(即序列化)来测试您实际正在测试的功能(即转换)。


3

我非常喜欢Fluent Assertions的ShouldBeEquivalentTo方法。

actual.ShouldBeEquivalentTo(expected);

默认情况下,假设传入的两个对象在结构上是相等的,这个比较功能就能够正常工作。但你可以提供其他参数来自定义比较方法。例如,如果你只想检查对象的某几个属性是否相等,你可以这么写:

actual.ShouldBeEquivalentTo(new {
    expected.Name,
    expected.Description,
    expected.Code
}, options =>
    options.ExcludingMissingMembers);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接