48 votes

Comment tester unitairement une méthode d'action qui renvoie JsonResult ?

Si j'ai un contrôleur comme celui-ci :

[HttpPost]
public JsonResult FindStuff(string query) 
{
   var results = _repo.GetStuff(query);
   var jsonResult = results.Select(x => new
   {
      id = x.Id,
      name = x.Foo,
      type = x.Bar
   }).ToList();

   return Json(jsonResult);
}

En gros, je récupère des éléments de mon référentiel, puis je les projette dans un fichier List<T> de types anonymes.

Comment puis-je faire un test unitaire ?

System.Web.Mvc.JsonResult a une propriété appelée Data mais il est de type object comme nous le pensions.

Cela signifie-t-il que si je veux tester que l'objet JSON possède les propriétés que j'attends ("id", "name", "type"), je dois utiliser la réflexion ?

EDIT :

Voici mon test :

// Arrange.
const string autoCompleteQuery = "soho";

// Act.
var actionResult = _controller.FindLocations(autoCompleteQuery);

// Assert.
Assert.IsNotNull(actionResult, "No ActionResult returned from action method.");
dynamic jsonCollection = actionResult.Data;
foreach (dynamic json in jsonCollection)
{
   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.");
}

Mais j'obtiens une erreur d'exécution dans la boucle, indiquant "object does not contain a definition for id".

Quand je fais un point d'arrêt, actionResult.Data est défini comme un List<T> de types anonymes, donc je me dis que si je les énumère, je peux vérifier les propriétés. Dans la boucle, l'objet fait ont une propriété appelée "id" - donc je ne suis pas sûr de la nature du problème.

0 votes

Concernant la modification, vous pouvez essayer quelque chose comme var items = (IEnumerable)actionResult.Data ; foreach(dynamic obj in items) {...}

1 votes

J'ai testé ici avec ` var list = (IList)data ; Assert.AreEqual(list.Count, 2) ; dynamic obj = data[0] ; Assert.AreEqual(obj.id, 12) ; Assert.AreEqual(obj.name, "Fred") ; Assert.AreEqual(obj.type, 'a') ; obj = data[1] ; Assert. AreEqual(obj.id,14) ; Assert.AreEqual(obj.name, "Jim") ; Assert.AreEqual(obj.type, 'c') ; foreach (dynamic d in list) { if (d.id == null) throw new InvalidOperationException() ; }` et ça semblait bien...

0 votes

Je vais essayer ce code demain quand je serai au bureau. merci.

1voto

Thai Anh Duc Points 254

Je prolonge la solution de Matt Greer et propose cette petite extension :

    public static JsonResult IsJson(this ActionResult result)
    {
        Assert.IsInstanceOf<JsonResult>(result);
        return (JsonResult) result;
    }

    public static JsonResult WithModel(this JsonResult result, object model)
    {
        var props = model.GetType().GetProperties();
        foreach (var prop in props)
        {
            var mv = model.GetReflectedProperty(prop.Name);
            var expected = result.Data.GetReflectedProperty(prop.Name);
            Assert.AreEqual(expected, mv);
        }
        return result;
    }

Et j'ai juste exécuté l'unittest comme ceci : - Définir le résultat des données attendues :

        var expected = new
        {
            Success = false,
            Message = "Name is required"
        };

- Affirmer le résultat :

        // Assert
        result.IsJson().WithModel(expected);

0voto

AssassinLV Points 28

Si, dans le test, vous savez exactement ce que le résultat des données Json doit être, vous pouvez simplement faire quelque chose comme ceci :

result.Data.ToString().Should().Be(new { param = value}.ToString());

P.S. Ce serait si vous aviez utilisé FluentAssertions.Mvc5 - mais il ne devrait pas être difficile de le convertir à n'importe quel outil de test que vous utilisez.

0voto

Harshal Points 19

Voici comment je l'affirme

foreach (var item in jsonResult.Data as dynamic) {
    ((int)item.Id).ShouldBe( expected Id value );
    ((string)item.name).ShouldBe( "expected name value" );
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X