2015-05-27 71 views
2

我想將xUnit理論與AutoFixture一起使用來生成匿名對象,但具有某些顯式屬性。使用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多「Do'基於定製的原因,但不知道爲什麼。

+0

你能包括'TaskState'源代碼和'SetProperty'呢? –

+0

「TestSomething」方法如何裝飾? –

+0

我更新了初始文章。 SetProperty只是使用反射來簡單地設置對象的屬性,AutoMoqData屬性應用默認AutoMoqCustomization –

回答

1

它不起作用,因爲每次下一次通過自定義類型自定義覆蓋以前的一個(感謝標記的解釋)。

所以我改變的定製配置類型,而不是它的屬性:

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; 
    } 
} 
4

你爲什麼不只是做以下?

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

    // The rest of the test... 
} 

or this?

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

    // The rest of the test... 
} 

這是簡單得多,而且類型安全的太...

+0

主要思想是完全(或多或少)在方法參數中移動排列語句。另外我相信[Task(InProgress)]任務通常更具可讀性/智能性,可以分解聲明和作業。當然,如果有超過2-3個參數設置,值得使用這種方法:) –

+1

...您選擇的編程語言*非常好*爲屬性賦值。爲什麼比這更難呢? –

+0

使測試更小。當然,如果測試足夠簡單並且只需要一個任務來分配這兩個屬性,我會明確地做到這一點。但想象一下,如果您需要以4-5次不同狀態和進度的操作,以適當的狀態測試任務。當然,你可以在安排階段明確地做到這一點,但我相信通過屬性來做到這一點可能會真正簡化進一步的測試閱讀和理解。畢竟,C#語法足夠好,完全可以在沒有xUnit屬性的情況下使用,只需要使用顯式的fixture實例即可。但我想嘗試這種方式 –