【问题标题】:Fluent Assertions: How to assert "single equivalent item in collection"?流利的断言:如何断言“集合中的单个等效项”?
【发布时间】:2021-11-21 08:00:05
【问题描述】:

在 MSTest 单元测试中,我需要断言给定的集合恰好包含与给定项等效的单个项,但流利的断言似乎只支持这些方法:

items.Should().ContainEquivalentOf(item);
items.Should().ContainSingle(item);

我需要两者的组合,比如“ContainSingleEquivalentOf(item)”(似乎不存在?)。

问题是 ContainSingle() 似乎只使用我需要的对象不支持的普通 Equals() 方法检查等价性,所以我需要使用流利断言提供的基于反射的等价性检查。但我不知道如何在这种情况下使用它。

编辑:允许该集合包含不符合我的条件的任意其他项目。

【问题讨论】:

  • items.Should().ContainSingle().And.ContainEquivalentOf(item); 怎么样?
  • @DavidG:因为 ContainSingle(item) 将始终为我返回 false,因为它使用 Equals() 而不是等价,这将不起作用。
  • 请注意我在ContainSingle 中没有给它一个项目?这意味着它只是检查集合中只有一个项目,下一步确保它具有正确的属性。
  • @DavidG:对不起,我的错,我的描述不够清楚,我编辑了我的帖子。

标签: c# unit-testing assertion fluent-assertions


【解决方案1】:

没有内置的方法可以断言一个集合只包含一个等价物。 但是由于 Fluent Assertions 的可扩展性,我们可以构建它。

这是ContainSingleEquivalentOf 的原型。 虽然它有一些限制。 例如。 Where(e => !ReferenceEquals(e, match.Which)) 断言它只会排除单个项目。

public static class Extensions
{
    public static AndWhichConstraint<GenericCollectionAssertions<T>, T> ContainSingleEquivalentOf<T, TExpectation>(this GenericCollectionAssertions<T> parent,
        TExpectation expected, string because = "", params string[] becauseArgs) => parent.ContainSingleEquivalentOf(expected, config => config, because, becauseArgs);

    public static AndWhichConstraint<GenericCollectionAssertions<T>, T> ContainSingleEquivalentOf<T, TExpectation>(this GenericCollectionAssertions<T> parent,
        TExpectation expected, Func<EquivalencyAssertionOptions<TExpectation>, EquivalencyAssertionOptions<TExpectation>> config, string because = "", params string[] becauseArgs)
    {
        var match = parent.ContainEquivalentOf(expected, config, because, becauseArgs);
        var remainingItems = parent.Subject.Where(e => !ReferenceEquals(e, match.Which)).ToList();

        remainingItems.Should().NotContainEquivalentOf(expected, config, because, becauseArgs);

        return match;
    }
}

请注意,Fluent Assertions 将使用Equals 在被期望覆盖以比较实例时。要覆盖该行为,您可以使用 ComparingByMembers 或提供匿名对象作为预期。

class MyClass
{
    public int MyProperty { get; set; }

    public override bool Equals(object obj) => false;
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void Force_comparing_by_members()
    {
        var subject = new MyClass[] { new() { MyProperty = 42 } };
        var expected = new MyClass { MyProperty = 42 };
        subject.Should().ContainSingleEquivalentOf(expected, opt => opt.ComparingByMembers<MyClass>());
    }

    [TestMethod]
    public void Use_anonymous_expectation_to_compare_by_members()
    {
        var subject = new MyClass[] { new() { MyProperty = 42 } };
        var expected = new { MyProperty = 42 };

        subject.Should().ContainSingleEquivalentOf(expected);
    }

    [TestMethod]
    public void Multiple_equivalent_items()
    {
        var subject = new MyClass[] { new() { MyProperty = 42 }, new() { MyProperty = 42 } };
        var expected = new { MyProperty = 42 };

        Action act = () => subject.Should().ContainSingleEquivalentOf(expected);

        act.Should().Throw<Exception>();
    }

    [TestMethod]
    public void No_equivalent_item()
    {
        var subject = new MyClass[] { new() { MyProperty = -1 } };
        var expected = new { MyProperty = 42 };

        Action act = () => subject.Should().ContainSingleEquivalentOf(expected);

        act.Should().Throw<Exception>();
    }

    [TestMethod]
    public void Fails_as_Fluent_Assertions_uses_overriden_Equals_method()
    {
        var subject = new MyClass[] { new() { MyProperty = 42 } };
        var expected = new MyClass { MyProperty = 42 };

        Action act = () => subject.Should().ContainSingleEquivalentOf(expected);

        act.Should().Throw<Exception>();
    }
}

【讨论】:

  • 对不起,如果我不够清楚,但我的收藏允许包含其他项目,只有一项符合我的条件。
猜你喜欢
  • 2013-09-24
  • 2020-03-16
  • 2012-02-18
  • 2016-10-19
  • 2022-03-23
  • 2022-07-23
  • 2020-02-08
  • 2014-07-27
  • 2020-02-18
相关资源
最近更新 更多