【问题标题】:Generate the same "random" values each test run in Autofixture在 Autofixture 中每次测试运行时生成相同的“随机”值
【发布时间】:2021-11-08 03:24:22
【问题描述】:

我想使用 Autofixture 创建具有随机值的(复杂)类型。只要所有值都不同,我不关心创建数据的价值。我想让Autofixture 在每次测试运行时创建相同的数据。

默认情况下,使用 Autofixture 的数据可能会导致测试有时通过有时失败。

为了更清楚一点。这是我正在寻找的行为的一个例子。这也应该适用于复杂类型,但我没有在示例中实现。

[Fact]
public void AlwaysTheSameValues()
{
    var semiRandomValues = new SemiRandomValues();
    int value1 = semiRandomValues.GetRandomInt(); // Always 145
    int value2 = semiRandomValues.GetRandomInt(); // Always 163
    int value3 = semiRandomValues.GetRandomInt(); // Always 153

    string value4 = semiRandomValues.GetRandomString(); // Always "NFNWLYGHLPLYAVYQHUVY"
    string value5 = semiRandomValues.GetRandomString(); // Always "ARNXRNCELHYQTAJIXMRC"

    Assert.True(value2>50); // This wil never fail
}

[Fact]
public void DifferentValuesEachRun()
{
    var semiRandomValues = new Fixture();
    int value1 = semiRandomValues.Create<int>(); // Produces a different result in each run
    int value2 = semiRandomValues.Create<int>(); // Produces a different result in each run
    int value3 = semiRandomValues.Create<int>(); // Produces a different result in each run

    string value4 = semiRandomValues.Create<string>(); // Produces a different result in each run
    string value5 = semiRandomValues.Create<string>(); // Produces a different result in each run

    Assert.True(value2 > 50); // This wil sometimes fail
}

使用这个类

public class SemiRandomValues
{
    private readonly Random _random = new Random(0); // The 0 makes all value the same each run

    public int GetRandomInt()
    {
        return _random.Next(1, 200);
    }

    public string GetRandomString()
    {
        var chars = Enumerable
            .Range(1, 20)
            .Select(_ => (char)_random.Next(65, 90))
            .ToArray();
        return new string(chars);
    }
}

注意:我不想依赖随机值(故意),但使用默认的 Autofixture 行为,我可以(意外地)检查未失败的工作单元测试。之后,当同事稍后运行该测试时,它可能会失败。对于那个同事来说,也很难重现失败的测试,因为测试可以在以后成功。

【问题讨论】:

    标签: autofixture


    【解决方案1】:

    我做了一个例子来说明几种方法。 一种方法是使用 DataAnnotations,另一种方法是创建自定义项,以确保您获得对您的情况有意义的默认值。

    马克·西曼wrote about this over a decade ago

    void Main()
    {
        var fixture = new Fixture().Customize(new MySpecimenBuilder().ToCustomization());
        for (int i = 0; i < 3; i++)
        {
            var foo = fixture.Create<Foo>();
            Console.WriteLine($"{i} Bar: {foo.Bar}, Baz: {foo.Baz}, Qux: {foo.Qux}");
            // Example output
            //0 Bar: 42, Baz: ABCDE983, Qux: 42
            //1 Bar: 42, Baz: ABCDE821, Qux: 42
            //2 Bar: 42, Baz: ABCDE974, Qux: 42
        }
    }
    
    public class Foo
    {
        public int Bar { get; set; }
    
        [RegularExpression(@"ABCDE\d{3}")]
        public string Baz { get; set; }
    
        [Range(42, 42)]
        public int Qux { get; set; }
    }
    
    public class MySpecimenBuilder : ISpecimenBuilder
    {
        public object Create(object request, ISpecimenContext context)
        {
            return request switch
            {
                PropertyInfo pi when pi.Name == nameof(Foo.Bar) => 42,
                _ => new NoSpecimen()
            };
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-11-27
      • 1970-01-01
      • 1970-01-01
      • 2013-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-07
      • 2013-12-10
      相关资源
      最近更新 更多