繁体   English   中英

使用 FluentAssertions 测试可选的等效性

[英]Testing Optional equivalence with FluentAssertions

我正在使用一个名为Optional ( https://github.com/nlkl/Optional ) 的库,它允许函数式语言常见的“可能”抽象。

该库很棒,但我在测试方面面临一个问题:我无法正确测试 2 个可选实例是否等效。

为了测试等效性,我使用Fluent Assertions 但是,我没有得到想要的结果。

我将用代码说明问题:

#load "xunit"

[Fact]
void TestOptional()
{
    var a = new[] { 1, 2, 3 }.Some();
    var b = new[] { 1, 2, 3 }.Some();
    
    a.Should().BeEquivalentTo(b);
}

这个测试失败了,正如我在屏幕截图中显示的(为了方便,我正在使用 LINQPad)

在此处输入图片说明

如您所见,这不是人们所期望的。

我如何告诉 Fluent Assertions 使用 Option 类型正确检查等效性?

更新

我在 Github 上打开了一个关于你的问题的问题,昨天 合并了一个 拉取请求,所以下一个(预)发布应该能让你优雅地解决你的问题:

新的重载允许您使用开放的泛型类型。 如果同时指定了开放类型和封闭类型,则封闭类型优先。

SelfReferenceEquivalencyAssertionOptions添加了以下方法:

  • public TSelf ComparingByMembers(System.Type type) { }
  • public TSelf ComparingByValue(System.Type type) { }

是添加到 Fluent Assertions 的单元测试,展示了它是如何工作的:

[Fact]
public void When_comparing_an_open_type_by_members_it_should_succeed()
{
    // Arrange
    var subject = new Option<int[]>(new[] { 1, 3, 2 });
    var expected = new Option<int[]>(new[] { 1, 2, 3 });

    // Act
    Action act = () => subject.Should().BeEquivalentTo(expected, opt => opt
        .ComparingByMembers(typeof(Option<>)));

    // Assert
    act.Should().NotThrow();
}

Fluent Assertions - 对象图比较说:

值类型

要确定 Fluent Assertions 是否应该递归到对象的属性或字段中,它需要了解哪些类型具有值语义以及哪些类型应该被视为引用类型。 默认行为是将覆盖 Object.Equals 的每个类型视为旨在具有值语义的对象 不幸的是,匿名类型和元组也覆盖了这个方法,但是因为我们倾向于在等价比较中经常使用它们,所以我们总是通过它们的属性来比较它们。

您可以通过为各个断言使用ComparingByValue<T>ComparingByMembers<T>选项轻松覆盖它

Option<T>是一个struct并覆盖Equals ,因此 Fluent Assertions 将ab与值语义进行比较。

Option<T>像这样实现Equals

public bool Equals(Option<T> other)
{
  if (!this.hasValue && !other.hasValue)
    return true;
  return this.hasValue
    && other.hasValue 
    && EqualityComparer<T>.Default.Equals(this.value, other.value);
}

因此int[]通过引用进行比较并且您的测试失败。

您可以为每个测试单独覆盖此行为,就像Guro Stron所说:

a.Should().BeEquivalentTo(b, opt => opt.ComparingByMembers<Option<int[]>>());

或者通过静态AssertionOptions类全局:

AssertionOptions.AssertEquivalencyUsing(options => 
    options.ComparingByMembers<Option<int[]>>());

编辑:

对于您的情况,Fluent Assertions 需要一个支持未绑定泛型类型的AssertEquivalencyUsing覆盖:

AssertionOptions.AssertEquivalencyUsing(options => 
    options.ComparingByMembers(typeof(Option<>)));

不幸的是,不存在这样的覆盖。

提出的另一个解决方案是扩展方法。 这是一个非常简单的实现:

public static class FluentAssertionsExtensions
{
    public static void BeEquivalentByMembers<TExpectation>(
        this ComparableTypeAssertions<TExpectation> actual,
        TExpectation expectation)
    {
        actual.BeEquivalentTo(
            expectation,
            options => options.ComparingByMembers<TExpectation>());
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM