随机枚举生成

问题描述 投票:0回答:4

我希望 AutoFixture 在我尝试创建的类型中包含该枚举时使用该枚举的随机值。基本上与此相同https://github.com/AutoFixture/AutoFixture/issues/360但对于枚举。

我尝试了以下方法,但 AutoFixture 尝试创建枚举而不是请求的类型,并且无法转换它。

public class RandomEnumSequenceGenerator<T> : ISpecimenBuilder where T : struct
{
    private static Random _random = new Random();
    private Array _values;

    public RandomEnumSequenceGenerator()
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("T must be an enum");
        }
        _values = Enum.GetValues(typeof(T));
    }

    public object Create(object request, ISpecimenContext context)
    {
        var index = _random.Next(0, _values.Length - 1);
        return _values.GetValue(index);
    }
}

然后我在我的 BaseUnitTest 类中使用它,如下所示

    public class BaseUnitTestClass
    {
        internal static Fixture _fixture = new Fixture();

        public BaseUnitTestClass()
        {               
            _fixture.Customizations.Add(new RandomEnumSequenceGenerator<TableType>());
        }

我拉下源代码,注意到它循环组成构建器,只有最后一个(RandomEnumSequenceGenerator)满足契约,然后它创建一个 TableType 枚举值并尝试将其转换为我要创建的实际类这会引发异常。

异常信息如下

at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext context, T seed)
  at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext context)
  at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenBuilder builder)
  at UnitTests.Unit.BaseUnitTestClass.GetRandomT in mypath\BaseUnitTestClass.cs:line 49
  Result Message:   System.InvalidCastException : Unable to cast object of type 'MyNamespace.TableType' to type 'MyNameSpace.AssumptionChangeCriteria'.

AsductionChangeCriteria 有一个类型为

TableType
的属性,它是一个枚举。

其中

GetRandom<T>
如下

return _fixture.Create<T>();
c# autofixture
4个回答
4
投票

您的

RandomEnumSequenceGenerator<T>
版本不会检查
request
,因此它仅响应 any 请求,即使它不是对其自定义类型的请求。

最简单的修复可能是这样的:

public class RandomEnumSequenceGenerator<T> : ISpecimenBuilder where T : struct
{
    private static Random _random = new Random();
    private Array _values;

    public RandomEnumSequenceGenerator()
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("T must be an enum");
        }
        _values = Enum.GetValues(typeof(T));
    }

    public object Create(object request, ISpecimenContext context)
    {
        var t = request as Type;
        if (t == null || t != typeof(T))
            return new NoSpecimen();

        var index = _random.Next(0, _values.Length - 1);
        return _values.GetValue(index);
    }
}

我还没有尝试编译和测试它,所以你可能需要稍微调整它,但它应该展示你必须做的事情的要点。


3
投票

修改了@mark-seemann的答案。请注意,

Random.Next
的上限是不包括的。

public class RandomEnumSequenceGenerator : ISpecimenBuilder
{
    private static readonly Random Random = new Random();

    public object Create(object request, ISpecimenContext context)
    {
        var seededRequest = request as SeededRequest;
        var type = seededRequest?.Request as Type;
        if (type == null || !type.IsEnum)
        {
            return new NoSpecimen();
        }

        var values = Enum.GetValues(type);
        var index = Random.Next(values.Length);
        return values.GetValue(index);
    }
}

用途:

Fixture.Customizations.Add(new RandomEnumSequenceGenerator());

1
投票

这应该修复类型转换异常,假设这是罪魁祸首:

public class RandomEnumSequenceGenerator<T> : ISpecimenBuilder where T : struct
{
    private static Random _random = new Random();
    private T[] _values;

    public RandomEnumSequenceGenerator()
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("T must be an enum");
        }

        _values = Enum.GetValues(typeof(T))
            .Cast<T>()
            .ToArray();
    }

    public object Create(object request, ISpecimenContext context)
    {
        var index = _random.Next(_values.Length);
        return _values[index];
    }
}

0
投票

上面的大部分内容都归功于 Mark Seeman,但这对我有用(调整了他的代码):

此更改很重要:

request as ParameterInfo

public class RandomEnumSequenceBuilder<T> : ISpecimenBuilder where T : struct
{
    private readonly T[] _values;

    public RandomEnumSequenceBuilder()
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("T must be an enum");
        }
        _values = Enum.GetValues(typeof(T)).Cast<T>().ToArray();
    }

    public object Create(object request, ISpecimenContext context)
    {
        var t = request as ParameterInfo;
        if (t == null || t.ParameterType != typeof(T))
            return new NoSpecimen();

        var index = Random.Shared.Next(0, _values.Length - 1);
        return _values.GetValue(index)!;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.