【问题标题】:xunit test Fact multiple timesxunit 多次测试事实
【发布时间】:2015-10-30 15:57:56
【问题描述】:

我有一些方法依赖于一些随机计算来提出建议,我需要多次运行 Fact 以确保一切正常。

我可以在我想要测试的事实中包含一个 for 循环,但是因为有几个测试我想要这样做,所以我正在寻找一种更简洁的方法,比如 junit 中的这个重复属性:http://www.codeaffine.com/2013/04/10/running-junit-tests-repeatedly-without-loops/

我可以在 xunit 中轻松实现类似的东西吗?

【问题讨论】:

    标签: c# random xunit


    【解决方案1】:

    您必须创建一个新的DataAttribute 来告诉 xunit 多次运行相同的测试。

    下面是一个与 junit 相同想法的示例:

    public class RepeatAttribute : DataAttribute
    {
        private readonly int _count;
    
        public RepeatAttribute(int count)
        {
            if (count < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(count), 
                      "Repeat count must be greater than 0.");
            }
            _count = count;
        }
    
        public override IEnumerable<object[]> GetData(MethodInfo testMethod)
        {
            return Enumerable.Repeat(new object[0], _count);
        }
    }
    

    使用此代码,您只需将Fact 更改为Theory 并使用Repeat,如下所示:

    [Theory]
    [Repeat(10)]
    public void MyTest()
    {
        ...
    }
    

    【讨论】:

    • 效果很好。不过,我确实必须从GetData 中删除Type[] parameterTypes 参数。现在,如果这仅适用于 CombinatorialData 等其他属性。
    • 我更新了示例代码以反映较新的 xunit API。谢谢!
    • 我已经更新了代码,使其可以与最新的 xunit 一起使用。只要repetitionNumber 是理论测试的参数,它就会起作用
    • 似乎不起作用@user357783 你能举个例子吗?
    • @Ywapom 我猜我的编辑在同行评审中丢失了。我刚刚尝试重新提交它们。同时,见gistlyn.com/?gist=52c37e37b51a0ec92810477be34695ae
    【解决方案2】:

    有相同的要求,但接受的答案代码没有重复测试,所以我将其调整为:

    public sealed class RepeatAttribute : Xunit.Sdk.DataAttribute
    {
        private readonly int count;
    
        public RepeatAttribute(int count)
        {
            if (count < 1)
            {
                throw new System.ArgumentOutOfRangeException(
                    paramName: nameof(count),
                    message: "Repeat count must be greater than 0."
                    );
            }
            this.count = count;
        }
    
        public override System.Collections.Generic.IEnumerable<object[]> GetData(System.Reflection.MethodInfo testMethod)
        {
            foreach (var iterationNumber in Enumerable.Range(start: 1, count: this.count))
            {
                yield return new object[] { iterationNumber };
            }
        }
    }
    

    虽然在前面的示例中使用了 Enumerable.Repeat,但它只会运行测试 1 次,但不知何故 xUnit 并没有重复测试。可能他们不久前改变了一些东西。 通过更改为foreach 循环,我们可以重复每个测试,但我们还提供了“迭代次数”。 在测试函数上使用它时,您必须向测试函数添加一个参数并将其装饰为Theory,如下所示:

    [Theory(DisplayName = "It should work")]
    [Repeat(10)]
    public void It_should_work(int iterationNumber)
    {
    ...
    }
    

    这适用于 xUnit 2.4.0。

    我创建了一个 NuGet package 来使用它以防万一有人感兴趣。

    【讨论】:

    • 感谢您注意到这一点,@ShanteshwarInde
    • 一个功能建议我有一个 [理论] 测试一个 Cache-Aside 模式。第一次运行会将数据插入分布式缓存,第二次从缓存中提取先前的数据,但是您的 nuget 似乎没有正确处理 [InlineData] 属性,即 [InlineData("myCacheKey")] (以及 VS2k19 中的 UI 16.3 有点乱)... :)
    • 感谢@alv 的反馈,但这似乎是对 xUnit 的功能请求... ;-)
    • 使用GetData 更短:return Enumerable.Range(1, this.count).Select(n =&gt; new object[] { n })
    【解决方案3】:

    我知道这是一个旧线程,但如果您需要重复测试少量次,可以应用以下小技巧:

    首先,创建一些虚拟数据:

    public static IEnumerable<object[]> DummyTestData()
    {
       yield return new object[] { 0 };
       yield return new object[] { 1 };
       yield return new object[] { 2 };
       yield return new object[] { 3 };
     }
    

    然后使用虚拟数据强制为每个向量运行测试。在这种情况下,相同的测试将被调用 4 次(但实际上没有使用虚拟数据):

    private static int _counter = 0;
    
    [Theory]
    [MemberData(nameof(DummyTestData))]
    public void SomeTest(int dummyParam)     // dummyParam is unused
    {
        _counter+= 1;
        DoSomething();
    
        Assert.True(...);           
    }    
    

    我发现这种方法非常有用,而且比创建新属性更简单。

    当然,如果您需要重复次数可参数化,这不是一个好的解决方案(尽管我确信有人可以建议一种方法使我的解决方案可参数化:-))。

    【讨论】:

      【解决方案4】:

      少量迭代的最简单方法:使其成为理论,而不是事实。 每次迭代插入一行[InlineData]

      using Xunit;
      
      namespace MyUnitTests
      {
          public class Class1
          {
      
              [Theory]
              [InlineData]
              [InlineData]
              public void TestThis()
              {
                  // test code here
              }
          }
      }
      

      使用 XUnit 2.4.1 测试

      【讨论】:

        【解决方案5】:

        由于MemberData 也为成员获取参数,您可以简单地传递迭代次数来创建“DummyTestData”。

        public static IEnumerable<object[]> MockParallel(int n)
        {
            foreach (var iterationNumber in Enumerable.Range(start: 1, count: n))
            {
                yield return new object[] { iterationNumber };
            }
        }
        

        现在您可以将重复次数作为参数传递。

        [Theory]
        [MemberData(nameof(MockParallel), n)] // repeat n times
        public void SomeTest(int repeat)
        

        【讨论】:

          【解决方案6】:

          您可以使用ITestCaseOrderer 订购测试。订购时,您可以指定一些测试多次次。例如

          using System.Collections.Generic;
          using System.Linq;
          using Xunit.Abstractions;
          using Xunit.Sdk;
          
          namespace XUnit.Project.Orderers {
              public class RepeatOrderer : ITestCaseOrderer {
                  public IEnumerable<TTestCase> OrderTestCases<TTestCase>(IEnumerable<TTestCase> testCases) where TTestCase : ITestCase {
                      List<TTestCase> result = new();
                      testCases.ToList().ForEach(testCase => {
                          var repeat = (ReflectionAttributeInfo)testCase.TestMethod.Method.GetCustomAttributes(typeof(RepeatAttribute)).FirstOrDefault();
                          if (repeat != null && repeat.Attribute is RepeatAttribute) {
                              var attr = repeat.Attribute as RepeatAttribute;
                              Enumerable.Range(0, attr.Count).ToList().ForEach((_) => { result.Add(testCase); });
                          }
                          else {
                              result.Add(testCase);
                          }
                      });
          
                      return result;
                  }
              }
          }
          

          属性

          public class RepeatAttribute : Attribute {
              public int Count { get; init; }
              public RepeatAttribute(int count) {
                  this.Count = count;
              }
          }
          

          指示测试项目使用orderer。在我的示例中,TestProject1 是 ordere 所在的程序集。

          [assembly : TestCaseOrderer("XUnit.Project.Orderers.RepeatOrderer", "TestProject1")]
          

          并使用Repeate属性

          [Fact]
          [Repeat(6)]
          public void Test1() {
          
          ...
          }
          
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-12-18
            • 1970-01-01
            • 2016-05-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-12-10
            • 1970-01-01
            相关资源
            最近更新 更多