5

我有以下两个课程:

public class KeyedEntity<TEntity>
{
    internal KeyedEntity() { }

    public Identifier Key { get; set; }
    public TEntity Entity { get; set; }
}

public static class KeyedEntity
{
    public static KeyedEntity<TEntity> Create<TEntity>(Identifier key, TEntity entity)
    {
        return new KeyedEntity<TEntity>
        {
            Key = key,
            Entity = entity,
        };
    }
}

构造函数internal和第二个类存在的原因是我想强制执行更高度可维护的KeyedEntity.Create(x, y)语法而不是new KeyedEntity<T>{ Key = x, Entity = y }. (请注意,类型是使用前一种语法推断的。)

我想告诉 AutoFixture 如何创建KeyedEntity. 但是,该Register方法似乎只允许注册单个类型而不是开放的泛型类型。

如何注册KeyedEntity.Create<TEntity>为创建功能KeyedEntity<TEntity>

4

2 回答 2

4

为了支持您的开放泛型类型,您可以编写自定义Specimen Builder

public class KeyedEntityBuilder : ISpecimenBuilder
{
    private readonly static MethodInfo createMethod =
        typeof(KeyedEntity).GetMethod("Create");

    public object Create(object request, ISpecimenContext context)
    {
        var t = request as Type;
        if (t == null ||
            !t.IsGenericType ||
            t.GetGenericTypeDefinition() != typeof(KeyedEntity<>))
            return new NoSpecimen(request);

        var entityType = t.GetGenericArguments().Single();

        var key = context.Resolve(typeof(Identifier));
        var entity = context.Resolve(entityType);

        return createMethod
            .MakeGenericMethod(entityType)
            .Invoke(null, new[] { key, entity });
    }
}

(为清楚起见,省略了防御性编码。)

以下单元测试通过:

public class Tests
{
    [Fact]
    public void CreateKeyedEntity()
    {
        var fixture = new Fixture();
        fixture.ResidueCollectors.Add(new KeyedEntityBuilder());

        var actual = fixture.Create<KeyedEntity<Foo>>();

        Assert.NotNull(actual.Key);
        Assert.NotNull(actual.Entity);
    }
}

为了更好的可维护性,您应该封装KeyedEntityBuilder在 Customization中。

于 2013-11-26T09:56:46.683 回答
0

假设您有一组派生类型,例如:

public class A: KeyedEntity<A>
{
}

public class B: KeyedEntity<B>
{
}

由于上面的对象图包含循环引用 (on T),您需要将Fixture实例配置为在第一次递归时省略分配:

然后你创建一个通用方法,该方法将为 自定义创建算法KeyedEntity<T>

internal void CustomizeKeyedEntity<T>(IFixture fixture)
{
    fixture.Customize<KeyedEntity<T>>(c =>
        c.FromFactory(() =>
            KeyedEntity.Create(
                fixture.Create<Identifier>(),
                fixture.Create<T>())));
}

您可以将上述方法用作:

this.CustomizeKeyedEntity<A>(fixture);
this.CustomizeKeyedEntity<B>(fixture);

例子

[Fact]
public void Test()
{
    var fixture = new Fixture();

    this.CustomizeKeyedEntity<A>(fixture);
    this.CustomizeKeyedEntity<B>(fixture);

    var actualA = fixture.Create<A>();
    var actualB = fixture.Create<B>();
}
于 2013-11-26T07:55:34.477 回答