繁体   English   中英

使用AutoFixture自定义显式设置样本的多个属性

[英]Explicitly Set up multiple properties of specimen using AutoFixture customizations

我想利用xUnit理论和AutoFixture来生成匿名对象,但具有一些显式属性。

那就是我现在所拥有的:

被测系统

public class Task
{
    public TaskState TaskState { get; set;}
    public int Progress { get; set; }
}

通用定制

public class PropertyCustomization<T> : ICustomization
{
    private readonly string propertyName;

    private readonly object value;

    public PropertyCustomization(string propertyName, object value)
    {
        this.propertyName = propertyName;
        this.value = value;
    }

    public void Customize(IFixture fixture)
    {
        fixture.Customize<T>(cmp => cmp.Do(obj => obj.SetProperty(this.propertyName, this.value)));
    }
}

..

public static void SetProperty(this object instance, string propertyName, object value)
{
    var propertyInfo = instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    propertyInfo.SetValue(instance, value);
}

并使用属性

[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AutoTaskAttribute : CustomizeAttribute
{
    private readonly int progress;

    private readonly TaskState taskState;

    public AutoTaskAttribute(TaskState taskState, int progress = -1)
    {
        this.taskState = taskState;
        this.progress = progress;
    }

    public override ICustomization GetCustomization(ParameterInfo parameter)
    {
        if (parameter == null)
        {
            throw new ArgumentNullException("parameter");
        }

        var result = new List<ICustomization> { new PropertyCustomization<Task>("TaskState", this.taskState) };

        if (this.progress > -1)
        {
            result.Add(new PropertyCustomization<Task>("Progress", this.progress));
        }

        return new CompositeCustomization(result);
    }
}

因此,如果我使用它仅指定那里的状态,它会很好地工作并建立匿名任务

[Theory, AutoMoqData]
public void TestSomething([AutoTask(TaskState.InProgress)]Task task)
{...}

但是,如果我想同时设置状态和进度,则出于某种原因,它仅设置了第二个属性,尽管两个“ Do”委托都被调用,但是在第二个调用中,它再次接收了具有默认状态的任务。

[Theory, AutoMoqData]
public void TestSomething([AutoTask(TaskState.InProgress, 50)]Task task)
{...}

我怀疑带有多个基于“做”的自定义的CompositeCustomization是原因,但不知道为什么。

您为什么不只执行以下操作?

[Theory, AutoMoqData]
public void TestSomething(Task task)
{
    task.TaskState = TaskState.InProgress;

    // The rest of the test...
}

或这个?

[Theory, AutoMoqData]
public void TestSomething(Task task)
{
    task.TaskState = TaskState.InProgress;
    task.Progress = 50;

    // The rest of the test...
}

这要简单得多,而且类型安全...

它不起作用,因为通过“自定义”进行的每个下一个Type自定义都将完全覆盖前一个(感谢Mark进行解释)。

所以我更改了自定义配置类型而不是其属性:

public class TypeCustomization<T> : ICustomization
{
    private List<Action<T>> actions;

    public TypeCustomization()
    {
        this.actions = new List<Action<T>>();
    }

    public void Customize(IFixture fixture)
    {
        fixture.Customize<T>(
            cmp =>
                {
                    return this.actions.Aggregate<Action<T>, IPostprocessComposer<T>>(cmp, (current, next) => current.Do(next));
                });
    }

    public TypeCustomization<T> With(string propertyName, object value)
    {
        this.actions.Add(obj => obj.SetProperty(propertyName, value));
        return this;
    }
}

它可以像这样在属性定义中使用:

[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AutoTaskAttribute : CustomizeAttribute
{
    private readonly int progress;

    private readonly TaskState taskState;

    public AutoTaskAttribute(TaskState taskState, int progress = -1)
    {
        this.taskState = taskState;
        this.progress = progress;
    }

    public override ICustomization GetCustomization(ParameterInfo parameter)
    {
        var customization = new TypeCustomization<Task>().With("TaskState", this.taskState);

        if (this.progress > -1)
        {
            customization.With("Progress", this.progress);
        }

        return customization;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM