【问题标题】:Why doesn't NUnit have an IsElementOf/IsOneOf constraint?为什么 NUnit 没有 IsElementOf/IsOneOf 约束?
【发布时间】:2011-06-18 01:49:18
【问题描述】:

我不直接使用 NUnit,但希望在不同的环境中借鉴它的一些想法。

一个特别优雅的想法是约束机制,它可以让您编写表单的单元测试:

Assert.That(aValue, Is.GreaterThan(2.0) & Is.LessThan(5.0));

您还可以测试某个值是否在某个范围内:

Assert.That(aValue, Is.InRange(2.0, 5.0));

但是,似乎没有办法测试 aValue 是否是允许值的集合之一:

Assert.That(aValue, Is.OneOf(aCollection));

在单元测试中不是很常见吗?它是否指出我的单元测试存在一些问题? 是不是每个人都只是将 aValue 注入到一些虚拟的 one 元素集合中,然后使用Is.SubsetOf

【问题讨论】:

    标签: unit-testing collections nunit dsl


    【解决方案1】:

    Assertion API 的全部内容都与可读性有关,而 Is.OneOf(collection) 对此的可读性没有任何好处:

    Assert.That(collection.Contains(value));
    

    它可读且清晰,因此如果没有任何结果,在 Assersion API 中复制每个案例是不正确的。据你所见,没有简单的方法可以替代 Is.InRange 和 Is.GreaterThan + Is.LessThan 比

    Assert.That(value > 2.0 && value < 5.0);
    //compared to
    Assert.That(value, Is.GraterThan(2.0).And.Is.LessThan(5.0));
    

    【讨论】:

    • 但同样的逻辑当然可以应用于Is.OneOf(collection):你可以将它与其他约束结合起来:Assert.That(value, Is.OneOf(Foo).And.Is.Not.OneOf(Bar))。同样collection.Contains(value) 将重点放在collection,而不是value
    • 它可以是好的也可以是坏的。某些集合具有值或集合中存在某些值取决于您要测试的内容。这不是相同的逻辑,我不是在谈论组合约束。我可以理解数字的组合约束,但我觉得很奇怪。 Is.OneOf(Foo).And.Is.Not.OneOf(Bar))。对我来说,有两个断言合二为一,这不是编写单元测试的好方法。
    【解决方案2】:

    当前版本的 NUnit (3.13) 有一个本地方法:Is.AnyOf(params object[] expected)

    你可以这样使用它:

    Assert.That(result, Is.AnyOf("red", "green", "blue"));
    Assert.That(result, Is.Not.AnyOf("black", "white"));
    

    【讨论】:

      【解决方案3】:

      @Lambdageek;

      Assert.That(aCollection, Has.Member(aValue) 
      Assert.That(aCollection, Has.No.Member(aValue) 
      

      已经有一段时间了。还有许多其他有用的集合约束,有据可查的here

      除了可读性之外,当出现故障时,您还可以获得更有用的反馈。值得付出微乎其微的额外努力,IMO。

      编辑

          [Test]
          public void Test() {
              var c = new[] {"one", "two"};
              Assert.That(c, Has.Member("three"));
          }
      
      Test failed:
        Expected: collection containing "three"
        But was:  < "one", "two" >
          Tests.cs(73,0): at ...Test()
      

      干杯,
      浆果

      穷人的约束

      public static class TestExtensions
      {
          public static bool IsOneOf<T>(this T candidate, IEnumerable<T> expected) {
              if (expected.Contains(candidate)) return true;
      
              var msg = string.Format("Expected one of: '{0}'. Actual: {1}", ", "._insertBetween(expected.Select(x => Convert.ToString(x))), candidate);
              Assert.Fail(msg);
              return false;
          }
      
          private static string _insertBetween(this string delimiter, IEnumerable<string> items)
          {
              var builder = new StringBuilder();
              foreach (var item in items)
              {
                  if (builder.Length != 0)
                  {
                      builder.Append(delimiter);
                  }
                  builder.Append(item);
              }
              return builder.ToString();
          }
      
          internal static IEnumerable<string> GenerateSplits(this string str, params char[] separators)
          {
              foreach (var split in str.Split(separators))
                  yield return split;
          }
      
      }
      

      测试失败

          [Test]
          public void IsOneOf_IfCandidateNotInRange_Error()
          {
              IEnumerable<string> expected = new[] { "red", "green", "blue" };
              const string candidate = "yellow";
              Assert.That(candidate.IsOneOf(expected));
          }
      
      IsOneOf_IfCandidateNotInRange_Error' failed:
      Expected one of: 'red, green, blue'. Actual: yellow
      

      【讨论】:

      • 正如我在回复@Restuta 的回答时提到的那样:在我看来,Assert.That(x, Has.Member(y)) 将重点放在x 上,而我真正测试的是y。特别是,如果单元测试失败,我希望错误消息告诉我aValue 的实际值,而不是aCollection 的实际值。
      • @Lambdageek - 见我上面的编辑。我以为您 正在 断言 aValue 在集合中,但也许我误解了您。如果不是,您究竟想要断言什么,以及来自失败测试的消息应该如何读取?如果是这样,那么现有的约束是怎样的呢?
      • 我想检查 aValue 是否由某个函数计算得出:aValue = Foo() 是一组允许值之一:Assert.That(aValue, Is.OneOf({"red", "green", "blue"}); 所以我希望错误消息说:“预期一个“红色”、“绿色”、“蓝色”。实际:“黄色””
      • @Lambdageek。明白了,不,我在 NUnit 中没有看到类似的东西。我确实保留了一个静态类 TestExtensions 用于那些(罕见的)当我需要比 NUnit 直接提供的更多的时候,所以编写你想要的扩展看起来就像我添加到我的答案中的代码。一旦你有了一些辅助方法(Skeet 的道具),这也真的不难做到。干杯
      猜你喜欢
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多