集合上的递归断言

发布于 2024-10-02 17:05:47 字数 372 浏览 8 评论 0原文

我想要一个这样的测试:

[Test]
    public void TestCollectionAssert ()
    {
        var a1 = new [] { new [] { "a" } };
        var a2 = new [] { new [] { "a" } };

        Assert.AreNotEqual (a1, a2);
        //CollectionAssert.AreEqual (a1, a2);
        CollectionAssert.AreEquivalent (a1, a2);
    }

通过。 我的真实案例更复杂,但以通用方式解决这个问题就可以了。 有什么想法吗?

I would like a test like this one:

[Test]
    public void TestCollectionAssert ()
    {
        var a1 = new [] { new [] { "a" } };
        var a2 = new [] { new [] { "a" } };

        Assert.AreNotEqual (a1, a2);
        //CollectionAssert.AreEqual (a1, a2);
        CollectionAssert.AreEquivalent (a1, a2);
    }

to pass.
My real case is more complicated, but solving this one in a generic way will do.
Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

掀纱窥君容 2024-10-09 17:05:47

有一个有用的 LINQ 运算符,名为 SequenceEqual() 比较两个序列是否相等。 SequenceEqual() 遍历任意两个 IEnumerable 序列并验证它们是否具有相同数量的元素和同一索引处的元素相等(使用默认的相等比较器)。但是,由于您有嵌套集合,因此您需要扩展相等的概念以也适用于它们。幸运的是,有一个重载允许您提供自己的 IEqualityComparer 对象。

由于经常需要定义一个类来提供相等语义很尴尬,因此我编写了一个通用扩展,允许您改用委托。让我们看一下代码:

public static class ComparerExt
{
    private class GenericComparer<T> : IEqualityComparer<T>
    {
        private readonly Func<T, T, bool> m_EqualityFunc;

        public GenericComparer( Func<T,T,bool> compareFunc )
        {
            m_EqualityFunc = compareFunc;
        }

        public bool Equals(T x, T y)
        {
            return m_EqualityFunc(x, y);
        }
    }

    // converts a delegate into an IComparer
    public static IEqualityComparer<T> AreEqual<T>( Func<T,T,bool> compareFunc )
    {
        compareFunc.ThrowIfNull("compareFunc");

        return new GenericComparer<T>(compareFunc);
    }
}

现在,我们可以很容易地比较两个序列:

Assert.IsTrue( 
   // check that outer sequences are equivalent...
   a1.SequenceEqual( a2,
                     // define equality as inner sequences being equal... 
                     ComparerExt.AreEqual( (a,b) => a.SequenceEqual(b) ) );

There's a useful LINQ operator called SequenceEqual() which compares two sequences for equality. SequenceEqual() walks through any two IEnumerable<> sequences and verifies that they have the same number of elements and that elements at the same index are equal (using the default equality comparer). However, since you have nested collections, you need to extend the concept of equality to apply to them as well. Fortunately, there's an overload that allows you supply your own IEqualityComparer<> object.

Since it's awkward to constantly have to define a class to provide equality semantics, I've written a generic extension that allows you to use a delegate instead. Let's look at the code:

public static class ComparerExt
{
    private class GenericComparer<T> : IEqualityComparer<T>
    {
        private readonly Func<T, T, bool> m_EqualityFunc;

        public GenericComparer( Func<T,T,bool> compareFunc )
        {
            m_EqualityFunc = compareFunc;
        }

        public bool Equals(T x, T y)
        {
            return m_EqualityFunc(x, y);
        }
    }

    // converts a delegate into an IComparer
    public static IEqualityComparer<T> AreEqual<T>( Func<T,T,bool> compareFunc )
    {
        compareFunc.ThrowIfNull("compareFunc");

        return new GenericComparer<T>(compareFunc);
    }
}

Now, we can compare two sequences easily enough:

Assert.IsTrue( 
   // check that outer sequences are equivalent...
   a1.SequenceEqual( a2,
                     // define equality as inner sequences being equal... 
                     ComparerExt.AreEqual( (a,b) => a.SequenceEqual(b) ) );
飘然心甜 2024-10-09 17:05:47

您可以编写如下所示的扩展方法。

public class AssertExtension
{
    public bool AreSimilar<T>(this CollectionAssert, IList<T> list1, IList<T> list2)
    {
        // ...
    }
}

问题当然是如何比较这两个列表。我建议逐步检查一个列表中的元素,并尝试将它们从另一个列表中删除。如果在执行此操作时出现问题或最后留下一些对象,则它们不相似。

You could write an extension method like the one below.

public class AssertExtension
{
    public bool AreSimilar<T>(this CollectionAssert, IList<T> list1, IList<T> list2)
    {
        // ...
    }
}

The problem is of course how to compare this two lists. I would suggest to step through the elements of the one list and try to remove them from the other. If there is a problem while doing this or at the end there are objects left they are not similar.

罪歌 2024-10-09 17:05:47

这是一个老问题,但有人刚刚在 nunit 讨论列表上发布了一个链接,所以我会回答。

NUnit 旨在报告两个列表相等。这就是它的工作原理。 Assert.NotEqual 实际上应该失败。

It's an old question, but somebody just posted a link on the nunit-discuss list, so I'll answer.

NUnit is designed to report the two lists as equal. That's just how it works. The Assert.NotEqual should in fact fail.

享受孤独 2024-10-09 17:05:47

我实现了以下方法,以递归方式比较元素。
到目前为止,它适用于我的所有测试用例,我可能会错过一个边缘情况。

    /// <summary>
    ///     Compares two enumerables recursively.
    /// </summary>
    /// <param name="left">IEnumerable</param>
    /// <param name="right">IEnumerable</param>
    /// <returns>bool</returns>
    public static bool SequenceEqual(this IEnumerable left, IEnumerable right)
    {
        if (ReferenceEquals(left, right))
        {
            return true;
        }

        if (ReferenceEquals(null, left))
        {
            return false;
        }


        if (left.GetType() != right.GetType())
        {
            return false;
        }

        var leftEnumerator = left.GetEnumerator();
        var rightEnumerator = right.GetEnumerator();

        while (leftEnumerator.MoveNext())
        {
            if (!rightEnumerator.MoveNext())
            {
                return false;
            }

            if (typeof(IEnumerable).IsAssignableFrom(leftEnumerator.Current.GetType()))
            {
                if (!typeof(IEnumerable).IsAssignableFrom(rightEnumerator.Current.GetType()))
                {
                    return false;
                }

                if (!SequenceEqual((IEnumerable)leftEnumerator.Current, (IEnumerable)rightEnumerator.Current))
                {
                    return false;
                }
            }
            else
            {
                if (!Equals(leftEnumerator.Current, rightEnumerator.Current))
                {
                    return false;
                }
            }
        }

        if (rightEnumerator.MoveNext())
        {
            return false;
        }

        return true;
    }

I implemented following method, to compare the elements recursively.
It worked so far for all my test cases, I could miss an edge case.

    /// <summary>
    ///     Compares two enumerables recursively.
    /// </summary>
    /// <param name="left">IEnumerable</param>
    /// <param name="right">IEnumerable</param>
    /// <returns>bool</returns>
    public static bool SequenceEqual(this IEnumerable left, IEnumerable right)
    {
        if (ReferenceEquals(left, right))
        {
            return true;
        }

        if (ReferenceEquals(null, left))
        {
            return false;
        }


        if (left.GetType() != right.GetType())
        {
            return false;
        }

        var leftEnumerator = left.GetEnumerator();
        var rightEnumerator = right.GetEnumerator();

        while (leftEnumerator.MoveNext())
        {
            if (!rightEnumerator.MoveNext())
            {
                return false;
            }

            if (typeof(IEnumerable).IsAssignableFrom(leftEnumerator.Current.GetType()))
            {
                if (!typeof(IEnumerable).IsAssignableFrom(rightEnumerator.Current.GetType()))
                {
                    return false;
                }

                if (!SequenceEqual((IEnumerable)leftEnumerator.Current, (IEnumerable)rightEnumerator.Current))
                {
                    return false;
                }
            }
            else
            {
                if (!Equals(leftEnumerator.Current, rightEnumerator.Current))
                {
                    return false;
                }
            }
        }

        if (rightEnumerator.MoveNext())
        {
            return false;
        }

        return true;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文