How do you unit test ASP.NET Core MVC Controllers that return anonymous objects?

前端 未结 1 1627
悲&欢浪女
悲&欢浪女 2020-11-30 10:50

I\'m having trouble unit testing ASP.NET Core MVC controllers that return anonymous objects. The unit testing is set up in a separate project and calls the controller method

相关标签:
1条回答
  • 2020-11-30 11:16

    Original idea from this answer with a more generic approach. Using a custom DynamicObject as a wrapper for inspecting the value via reflection there was no need to add the 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);
        }
    }
    

    Assuming the following controller

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

    Tests could look like

    [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 讨论(0)
提交回复
热议问题