2016-07-18 46 views
8

我在單元測試返回匿名對象的ASP.NET Core MVC控制器時遇到問題。單元測試在單獨的項目中設置,並直接從主項目調用控制器方法。你如何測試返回匿名對象的ASP.NET Core MVC控制器?

控制器方法返回IActionResult,但通常這些是OkObjectResultBadRequestObjectResult對象,該對象通過適當的HTTP狀態代碼轉換爲JSON響應。匿名對象作爲ObjectResult對象的構造函數參數傳遞,正是這些我試圖對此作出斷言(可通過ObjectResult.Value訪問)。

我發現這個問題(how can i access internals in asp.net 5)即有說,使用動態,並添加

[assembly: InternalsVisibleTo("Namespace")] 

到AssemblyInfo.cs中,可以在測試項目中獲得的匿名對象的內部對象屬性的答案。但是,最新版本的ASP.NET Core MVC沒有AssemblyInfo.cs,並且如鏈接問題的答案中所建議的那樣添加一個也不起作用。

現在是否有不同的位置添加InternalsVisibleTo或我缺少什麼?

+0

HTTP ://stackoverflow.com/questions/9956648/how-do-i-check-if-a-property-exists-on-a-dynamic-anonymous-type-in​​-c –

回答

16

this answer的最初想法與更通用的方法。使用自定義DynamicObject作爲包裝器通過反射檢查值沒有必要添加InternalsVisibleTo

public class DynamicObjectResultValue : DynamicObject, IEquatable<DynamicObjectResultValue> { 
    private readonly object value; 

    public DynamicObjectResultValue(object value) { 
     this.value = value; 
    } 

    #region Operators 
    public static bool operator ==(DynamicObjectResultValue a, DynamicObjectResultValue b) { 
     // If both are null, or both are same instance, return true. 
     if (System.Object.ReferenceEquals(a, b)) { 
      return true; 
     } 
     // If one is null, but not both, return false. 
     if (ReferenceEquals((object)a, null) || ReferenceEquals((object)b, null)) { 
      return false; 
     } 
     // Return true if the fields match: 
     return a.value == b.value; 
    } 

    public static bool operator !=(DynamicObjectResultValue a, DynamicObjectResultValue b) { 
     return !(a == b); 
    } 
    #endregion 

    public override IEnumerable<string> GetDynamicMemberNames() { 
     return value.GetType().GetProperties().Select(p => p.Name); 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) { 
     //initialize value 
     result = null; 
     //Search possible matches and get its value 
     var property = value.GetType().GetProperty(binder.Name); 
     if (property != null) { 
      // If the property is found, 
      // set the value parameter and return true. 
      var propertyValue = property.GetValue(value, null); 
      result = propertyValue; 
      return true; 
     } 
     // Otherwise, return false. 
     return false; 
    } 

    public override bool Equals(object obj) { 
     if (obj is DynamicObjectResultValue) 
      return Equals(obj as DynamicObjectResultValue); 
     // If parameter is null return false. 
     if (ReferenceEquals(obj, null)) return false; 
     // Return true if the fields match: 
     return this.value == obj; 
    } 

    public bool Equals(DynamicObjectResultValue other) { 
     // If parameter is null return false. 
     if (ReferenceEquals(other, null)) return false; 
     // Return true if the fields match: 
     return this.value == other.value; 
    } 

    public override int GetHashCode() { 
     return ToString().GetHashCode(); 
    } 

    public override string ToString() { 
     return string.Format("{0}", value); 
    } 
} 

假設下面的控制器

public class FooController : Controller { 

    public IActionResult GetAnonymousObject() { 

     var jsonResult = new { 
      id = 1, 
      name = "Foo", 
      type = "Bar" 
     }; 

     return Ok(jsonResult); 
    } 

    public IActionResult GetAnonymousCollection() { 

     var jsonResult = Enumerable.Range(1, 20).Select(x => new { 
      id = x, 
      name = "Foo" + x, 
      type = "Bar" + x 
     }).ToList(); 

     return Ok(jsonResult); 
    } 
} 

測試可能看起來像

[TestMethod] 
public void TestDynamicResults() { 
    //Arrange 
    var controller = new FooController(); 

    //Act 
    var result = controller.GetAnonymousObject() as OkObjectResult; 

    //Assert 
    dynamic obj = new DynamicObjectResultValue(result.Value); 

    Assert.IsNotNull(obj); 
    Assert.AreEqual(1, obj.id); 
    Assert.AreEqual("Foo", obj.name); 
    Assert.AreEqual(3, obj.name.Length); 
    Assert.AreEqual("Bar", obj.type); 
} 

[TestMethod] 
public void TestDynamicCollection() { 
    //Arrange 
    var controller = new FooController(); 

    //Act 
    var result = controller.GetAnonymousCollection() as OkObjectResult; 

    //Assert 
    Assert.IsNotNull(result, "No ActionResult returned from action method."); 
    dynamic jsonCollection = result.Value; 
    foreach (dynamic value in jsonCollection) { 
     dynamic json = new DynamicObjectResultValue(value); 

     Assert.IsNotNull(json.id, 
      "JSON record does not contain \"id\" required property."); 
     Assert.IsNotNull(json.name, 
      "JSON record does not contain \"name\" required property."); 
     Assert.IsNotNull(json.type, 
      "JSON record does not contain \"type\" required property."); 
    } 
} 
+0

這是一個真正的ele適用於不再使用AssemblyInfo的ASP.NET Core MVC項目的gant解決方案。完美的作品,所以我接受它作爲答案。 – Jargon

+0

這真棒!給我97%的需求:)現在,約3%...是否有可能獲得jsonCollection的長度?並且需要什麼來獲得,比如jsonCollection [0],所以我可以斷言不僅是NotNull,而且還有實際的值:'Assert.Equal(4,jsonCollection.Count())'和'Assert.Equal(25 ,jsonCollection [0] .id)'。如果你想讓我開始一個新的線程 - 高興做到這一點! – Felix

+1

@Felix添加主題並讓我知道。自從把它放在這裏以來,我一直致力於完善這項工作。當我有機會時,我會看看你評論中的細節。離開我的頭頂。對於'jsonCollection [0]'我想'覆蓋TryGetIndex'。因爲你正在處理'dynamic',即'Assert.Equal(4,(int)jsonCollection.Count())',所以你必須施放。我一直在努力做到像你一樣,但目前爲止沒有骰子。鑄造似乎工作,所以我堅持這一點。 – Nkosi

相關問題