2016-07-18 1 views
8

Je rencontre des difficultés pour tester les contrôleurs ASP.NET Core MVC qui retournent des objets anonymes. Le test unitaire est mis en place dans un projet séparé et appelle directement les méthodes du contrôleur du projet principal.Comment testez-vous les contrôleurs ASP.NET Core MVC qui retournent des objets anonymes?

Les méthodes du contrôleur renvoient IActionResult mais généralement ce sont les objets OkObjectResult et BadRequestObjectResult qui sont traduits dans une réponse JSON avec le code d'état HTTP approprié. Les objets anonymes sont passés en tant que paramètres constructeurs pour les objets ObjectResult et ce sont ceux-ci que j'essaie de faire valoir (par l'intermédiaire de ObjectResult.Value).

Je trouve cette question (how can i access internals in asp.net 5) qui a une réponse qui dit d'utiliser la dynamique et ajouter

[assembly: InternalsVisibleTo("Namespace")] 

à AssemblyInfo.cs pour permettre l'accès au projet de test aux propriétés de l'objet internes des objets anonymes. Cependant, les dernières versions d'ASP.NET Core MVC n'ont pas AssemblyInfo.cs et en ajouter une comme suggéré dans les réponses à la question liée ne fonctionne pas non plus.

Y a-t-il un emplacement différent pour ajouter le InternalsVisibleTo ou est-ce qu'il me manque quelque chose?

+0

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

Répondre

16

Idée originale de this answer avec une approche plus générique. En utilisant une coutume DynamicObject comme emballage pour inspecter la valeur par réflexion il n'y avait pas besoin d'ajouter le 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); 
    } 
} 

En supposant que le contrôleur suivant

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 pourraient ressembler à

[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

Ceci est vraiment ele solution gant pour les projets ASP.NET Core MVC qui n'utilisent plus AssemblyInfo. Fonctionne parfaitement, donc je l'ai accepté comme réponse. – Jargon

+0

C'est génial! Donne-moi 97% de ce dont j'ai besoin :) Maintenant, à propos de ce 3% ... Est-il possible d'obtenir la longueur de jsonCollection? et que faudrait-il pour obtenir, disons, jsonCollection [0], donc je peux affirmer non seulement NotNull, mais aussi la valeur réelle: 'Assert.Equal (4, jsonCollection.Count())' et 'Assert.Equal (25 , jsonCollection [0] .id) '. Si vous voulez que je commence un nouveau fil - heureux de faire cela! – Felix

+1

@Felix Ajoutez le fil et faites le moi savoir. J'ai travaillé sur le raffinement de ce travail depuis que je l'ai mis ici. Quand j'en aurai l'occasion, je regarderai les détails dans votre commentaire. Du haut de ma tête. pour 'jsonCollection [0]' je pense 'override TryGetIndex'. pour les affirmations que vous avez à lancer parce que vous avez affaire à 'dynamic', c'est-à-dire' Assert.Equal (4, (int) jsonCollection.Count()) '. J'ai essayé de le faire comme toi mais jusqu'ici aucun dé. la coulée semblait fonctionner, donc je suis resté avec ça. – Nkosi