如何对返回匿名对象的ASP.NET Core MVC控制器进行unit testing?

我在unit testing返回匿名对象的ASP.NET Core MVC控制器时遇到了麻烦。 unit testing在单独的项目中设置,并直接从主项目调用控制器方法。

控制器方法返回IActionResult但通常这些是OkObjectResultBadRequestObjectResult对象,它们被转换为具有适当HTTP状态代码的JSON响应。 匿名对象作为ObjectResult对象的构造函数参数传递,我正在尝试对其进行断言(可通过ObjectResult.Value访问)。

我发现这个问题(我如何访问asp.net 5中的内部 )有一个答案,说使用动态和添加

 [assembly: InternalsVisibleTo("Namespace")] 

到AssemblyInfo.cs,允许测试项目访问匿名对象的内部对象属性。 但是,最新版本的ASP.NET Core MVC没有AssemblyInfo.cs,并且在链接问题的答案中建议添加一个也不起作用。

是否现在有一个不同的位置来添加InternalsVisibleTo或我错过了什么?

从这个答案的原始想法与更通用的方法。 使用自定义DynamicObject作为包装器通过reflection检查值,无需添加InternalsVisibleTo

 public class DynamicObjectResultValue : DynamicObject, IEquatable { 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 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."); } }