【问题标题】:two-way list comparison in C# unit testC#单元测试中的双向列表比较
【发布时间】:2010-01-04 19:56:22
【问题描述】:

在我的 C# 单元测试中,我经常根据 ID 列表查询行列表。然后我想确保 1) 对于所有 ID,至少找到一个具有该 ID 的行,并且 2) 对于所有返回的行,每一行都有一个 ID,该 ID 在要查找的 ID 列表中。以下是我通常如何确保:

Assert.IsTrue(ids.All(
    id => results.Any(result => result[primaryKey].Equals(id))
), "Not all IDs were found in returned results");

Assert.IsTrue(results.All(
    result => ids.Any(id => result[primaryKey].Equals(id))
), "Returned results had unexpected IDs");

我认为使用AnyAll 进行此类检查很方便,但我想看看是否有人认为这比它可能的可读性差,或者是否有更好的方法来做两个-像这样的方式检查。我在 Visual Studio 2008 Team System 中使用 MSTest 进行单元测试。如果过于主观,这也许应该是社区 wiki。

编辑:我现在正在使用基于 Aviad P. 建议的解决方案,以及以下测试通过的事实:

string[] ids1 = { "a", "b", "c" };
string[] ids2 = { "b", "c", "d", "e" };
string[] ids3 = { "c", "a", "b" };
Assert.AreEqual(
    1,
    ids1.Except(ids2).Count()
);
Assert.AreEqual(
    2,
    ids2.Except(ids1).Count()
);
Assert.AreEqual(
    0,
    ids1.Except(ids3).Count()
);

【问题讨论】:

    标签: c# unit-testing coding-style readability


    【解决方案1】:

    您可以选择使用Except 运算符:

    var resultIds = results.Select(x => x[primaryKey]);
    
    Assert.IsTrue(resultIds.Except(ids).Count() == 0,
     "Returned results had unexpected IDs");
    
    Assert.IsTrue(ids.Except(resultIds).Count() == 0,
     "Not all IDs were found in returned results");
    

    【讨论】:

    • 这看起来不错,我喜欢我只写一次x[primaryKey]。不过,考虑到Except 的描述方式,我认为应该是Count() == 0
    • 其实你需要保留>0,但是交换消息。修改了我的答案。
    • 为什么需要>0?我希望检索到的结果 ID 列表和我查询的 ID 列表之间没有区别。 Intellisense 将Except 描述为产生“两个序列的集合差异”。
    • Count() == 0 的更好替代品是Any()
    • 我最终没有使用Count() == 0Any(),而是使用Assert.AreEqualCount()0
    【解决方案2】:

    IMO,没有它应有的可读性。创建并记录一个返回真/假的方法。然后调用 Assert.IsTrue(methodWithDescriptiveNameWhichReturnsTrueOrfalse(), "reason for failure");

    【讨论】:

    • +1 这本质上是 Custom Assertion xUnit 测试模式,尽管您不妨将其设为 void 方法并将断言移入方法中。
    【解决方案3】:

    这是我为处理两个可枚举而编写的代码的 sn-p,并在 MS 测试中进行单元测试时抛出异常,它可能会有所帮助:

    使用

    比较两个枚举:

     MyAssert.AreEnumerableSame(expected,actual);
    

    管理异常

    MyAssert.Throws<KeyNotFoundException>(() => repository.GetById(1), string.Empty);
    

    代码

    public class MyAssert
        {
            public class AssertAnswer
            {
                public bool Success { get; set; }
                public string Message { get; set; }
            }
    
            public static void Throws<T>(Action action, string expectedMessage) where T : Exception
            {
                AssertAnswer answer = AssertAction<T>(action, expectedMessage);
    
                Assert.IsTrue(answer.Success);
                Assert.AreEqual(expectedMessage, answer.Message);
            }
    
            public static void AreEnumerableSame(IEnumerable<object> enumerable1, IEnumerable<object> enumerable2)
            {
                bool isSameEnumerable = true;
                bool isSameObject ;
    
                if (enumerable1.Count() == enumerable2.Count())
                {
                    foreach (object o1 in enumerable1)
                    {
                        isSameObject = false;
                        foreach (object o2 in enumerable2)
                        {
                            if (o2.Equals(o1))
                            {
                                isSameObject = true;
                                break;
                            }
                        }
                        if (!isSameObject)
                        {
                            isSameEnumerable = false;
                            break;
                        }
                    }
                }
                else
                    isSameEnumerable = false;
    
                Assert.IsTrue(isSameEnumerable);
            }
    
            public static AssertAnswer AssertAction<T>(Action action, string expectedMessage) where T : Exception
            {
                AssertAnswer answer = new AssertAnswer();
    
                try
                {
                    action.Invoke();
    
                    answer.Success = false;
                    answer.Message = string.Format("Exception of type {0} should be thrown.", typeof(T));
                }
                catch (T exc)
                {
                    answer.Success = true;
                    answer.Message = expectedMessage;
                }
                catch (Exception e)
                {
                    answer.Success = false;
                    answer.Message = string.Format("A different Exception was thrown {0}.", e.GetType());
                }
    
                return answer;
            }
        }
    

    【讨论】:

      【解决方案4】:

      NUnit 有 CollectionAssert 系列断言,有助于提高可读性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-18
        • 2018-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-19
        相关资源
        最近更新 更多