Des tests unitaires sur le MVC de validation
Comment puis-je tester que mon contrôleur de l'action est de mettre la correction d'erreurs dans le ModelState lors de la validation d'une entité, lorsque je suis en utilisant DataAnnotation de validation dans MVC 2 Extrait 1?
Un peu de code pour illustrer. Tout d'abord, l'action:
[HttpPost]
public ActionResult Index(BlogPost b)
{
if(ModelState.IsValid)
{
_blogService.Insert(b);
return(View("Success", b));
}
return View(b);
}
Et voici un échec de test de l'unité qui, je pense, devrait passer mais n'est-ce pas (à l'aide de MbUnit & Moq):
[Test]
public void When_processing_invalid_post_HomeControllerModelState_should_have_at_least_one_error()
{
//arrange
var mockRepository = new Mock<IBlogPostSVC>();
var homeController = new HomeController(mockRepository.Object);
//act
var p = new BlogPost { Title = "test" }; //date and content should be required
homeController.Index(p);
//assert
Assert.IsTrue(!homeController.ModelState.IsValid);
}
Je pense en plus à cette question, devrait j'essai de validation, et que je devrais tester de cette façon?
- N'est-ce pas var p = nouvel article sur le Blog { Title = "test" }; plus Organiser de Loi?
- Affirmer.IsFalse(homeController.ModelState.IsValid);
Vous devez vous connecter pour publier un commentaire.
Au lieu de passer dans un
BlogPost
vous pouvez également déclarer les actions paramètre commeFormCollection
. Ensuite, vous pouvez créer leBlogPost
- vous et appelezUpdateModel(model, formCollection.ToValueProvider());
.Cela va déclencher la validation pour un champ de l'
FormCollection
.Assurez-vous que votre test ajoute une valeur null pour chaque champ dans la vue formulaire que vous souhaitez laisser vide.
J'ai trouvé que cette façon de faire, au détriment de quelques lignes de code supplémentaires, fait mes tests d'unité ressemble à la façon dont le code est appelé lors de l'exécution de plus près les rendant plus précieux. Aussi, vous pouvez tester ce qui se passe quand quelqu'un entre dans "abc" dans un contrôle lié à un int propriété.
Déteste nécro un vieux post, mais j'ai pensé que je pourrais ajouter mes propres pensées (depuis que j'ai juste eu ce problème et a couru à travers ce post en cherchant la réponse).
Ce que vous voulez vraiment tester ici est que votre contrôleur est-ce que vous attendez à faire lors de la validation échoue. C'est votre code et vos attentes. Des tests, il est facile une fois que vous vous rendez compte que tout ce que vous voulez tester:
J'avais eu le même problème, et après la lecture de Pauls réponse et commentaire, j'ai cherché un moyen de manuellement la validation du modèle de vue.
J'ai trouvé ce tutoriel qui explique comment valider manuellement un ViewModel qui utilise DataAnnotations. On a extrait de code est vers la fin du post.
J'ai modifié le code légèrement - dans le tutoriel, le 4ème paramètre de la TryValidateObject est omis (validateAllProperties). Afin d'obtenir toutes les annotations pour Valider, ce doit être défini à true.
De plus j'ai refait le code dans une méthode générique, pour effectuer des tests de ViewModel de validation simple:
Jusqu'à présent cela a vraiment bien fonctionné pour nous.
var key = validationResult.MemberNames.Any() ? validationResult.MemberNames.First() : string.Empty; controller.ModelState.AddModelError(key, validationResult.ErrorMessage);
Lorsque vous appelez le contrôleur homeController.Méthode de l'indice dans votre test, vous ne l'utilisez pas tout de le framework MVC qui déclenche la validation de sorte ModelState.IsValid sera toujours vrai. Dans notre code, nous appelons à un assistant de Valider la méthode directement dans le contrôleur plutôt que d'utiliser ambiante de validation. Je n'ai pas eu beaucoup d'expérience avec le DataAnnotations (Nous utilisons NHibernate.Les validateurs) peut-être quelqu'un d'autre peut offrir des conseils comment appeler Valider à partir de votre contrôleur.
Je faisais des recherches sur cette question aujourd'hui, et j'ai trouvé ce blog par Roberto Hernández (MVP) qui semble fournir la meilleure solution pour tirer les validateurs pour une action de contrôleur au cours de tests unitaires. Cela mettra l'corriger des erreurs dans la ModelState lors de la validation d'une entité.
Je suis en utilisant ModelBinders dans mon cas de test pour être en mesure de mettre à jour le modèle.IsValid valeur.
Avec mon MvcModelBinder.BindModel méthode comme suit (en gros le même code utilisé
à l'interne dans le framework MVC):
controller.ModelState.Clear();
avant le code qui créeModelBindingContext
et cela fonctionneCe n'est pas exactement la réponse à votre question, parce qu'il abandonne DataAnnotations, mais je vais l'ajouter car il pourrait aider d'autres personnes à écrire des tests pour leurs Contrôleurs:
Vous avez la possibilité de ne pas utiliser la validation prévue par le Système.ComponentModel.DataAnnotations mais toujours en utilisant le ViewData.ModelState objet, à l'aide de son
AddModelError
méthode et quelques autres le mécanisme de validation. E. g:Cela permet toujours de profiter de la
Html.ValidationMessageFor()
trucs qui MVC génère, sans l'aide de laDataAnnotations
. Vous devez assurez-vous que la clé que vous utilisez avecAddModelError
correspond à ce que l'avis est attendu pour la validation des messages.Le contrôleur devient alors testable parce que la validation se passe de manière explicite, plutôt que d'être fait automatiquement par le framework MVC.
Je suis d'accord que le BRAS a la meilleure réponse: tester le comportement de votre contrôleur, pas la validation intégrée.
Cependant, vous pouvez également l'unité de test d'un Modèle/ViewModel a la bonne validation attributs définis. Disons que votre ViewModel ressemble à ceci:
Ce test permettra de tester l'existence de la
[Required]
attribut:Contrairement aux BRAS, je n'ai pas de problème avec fossoyage. Donc, voici ma suggestion. Il s'appuie sur la réponse de Giles Smith et travaille pour ASP.NET MVC4 (je sais que la question est à propos de MVC 2, mais Google ne fait pas de discrimination lors de la recherche de réponses et je ne peux pas tester sur MVC2.)
Au lieu de mettre le code de validation dans le générique de la méthode statique, je l'ai mis dans un contrôleur de test. Le contrôleur dispose de tout le nécessaire pour la validation. Ainsi, le contrôleur de test ressemble à ceci:
Bien sûr, la classe n'a pas besoin d'être protégé innerclass, c'est la façon dont je l'utilise maintenant, mais je suis probablement aller à la réutilisation de cette classe. Si il y a quelque part un modèle Monmodèle qui est décoré avec de belles annotation de données d'attributs, le test ressemble à quelque chose comme ceci:
L'avantage de cette configuration est que je peux réutiliser le contrôleur de test pour les tests de tous mes modèles et peut être en mesure de le prolonger pour se moquer un peu plus sur le contrôleur ou de l'utilisation de l'objet protégé méthodes d'un contrôleur.
Espère que cela aide.
Si vous vous souciez de la validation, mais vous ne vous inquiétez pas sur la façon dont il est mis en œuvre, si vous ne se soucient que de la validation de votre méthode d'action au plus haut niveau d'abstraction, peu importe si elle est mise en œuvre que l'utilisation de DataAnnotations, ModelBinders ou même ActionFilterAttributes, vous pouvez vous servir de Xania.AspNet.Simulateur de package nuget comme suit:
--
Basé sur @giles-smith 's réponse et les commentaires, pour les API Web:
Voir sur répondre à modifier ci-dessus...
@giles-smith réponse est mon approche préférée mais la mise en œuvre peut être simplifiée: