Come si esegue il test unitario dei controller MVC di base ASP.NET che restituiscono oggetti anonimi?

Sto riscontrando dei problemi con l’unità test dei controller ASP.NET Core MVC che restituiscono oggetti anonimi. Il test dell’unità è impostato in un progetto separato e chiama direttamente i metodi del controllore dal progetto principale.

I metodi del controller restituiscono IActionResult ma in genere si tratta di oggetti OkObjectResult e BadRequestObjectResult che vengono tradotti in una risposta JSON con il codice di stato HTTP appropriato. Gli oggetti anonimi vengono passati come parametri del costruttore per gli oggetti ObjectResult e sono questi che sto cercando di fare delle asserzioni contro (accessibili tramite ObjectResult.Value ).

Ho trovato questa domanda ( come posso accedere agli interni in asp.net 5 ) che ha una risposta che dice di usare la dynamic e aggiungere

 [assembly: InternalsVisibleTo("Namespace")] 

su AssemblyInfo.cs per consentire al progetto di test di accedere alle proprietà dell’object interno degli oggetti anonimi. Tuttavia, le ultime versioni di ASP.NET Core MVC non hanno AssemblyInfo.cs e l’aggiunta di una come suggerito nelle risposte alla domanda collegata non funziona neanche.

C’è ora una posizione diversa per aggiungere il InternalsVisibleTo o mi manca qualcosa?

Idea originale da questa risposta con un approccio più generico. Utilizzando DynamicObject personalizzato come wrapper per ispezionare il valore tramite riflessione, non è stato necessario aggiungere 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); } } 

Supponendo il seguente 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); } } 

I test potrebbero essere simili

 [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."); } }