Devez-vous tester les propriétés simples d’une classe en affirmant qu’une valeur est définie et extraite? Ou est-ce vraiment juste l'unité qui teste la langue?
Exemple
public string ConnectionString { get; set; }
Test
public void TestConnectionString()
{
var c = new MyClass();
c.ConnectionString = "value";
Assert.Equal(c.ConnectionString, "value");
}
Je suppose que je ne vois pas la valeur en cela.
Je suggérerais que vous devriez absolument.
Qu'est-ce qu'une auto-propriété aujourd'hui peut finir par avoir un champ de support contre elle demain, et pas par vous ...
L'argument selon lequel "vous ne testez que le compilateur ou le framework" est un peu un imbécile; ce que vous faites lorsque vous testez une propriété automatique, c'est, du point de vue de l'appelant, de tester "l'interface" publique de votre classe. L'appelant n'a aucune idée s'il s'agit d'une propriété auto avec un magasin de support généré par la structure ou s'il existe un million de lignes de code complexe dans le getter/setter. Par conséquent, l'appelant teste le contrat impliqué par la propriété _ que si vous mettez X dans la boîte, vous pourrez le récupérer ultérieurement.
Par conséquent, il nous incombe d'inclure un test puisque nous testons le comportement de notre propre code et non celui du compilateur.
Un test comme celui-ci prend peut-être une minute à écrire, donc ce n’est pas vraiment fastidieux; et vous pouvez facilement créer un modèle T4 qui générera automatiquement ces tests avec un peu de réflexion. Je travaille actuellement sur un tel outil pour sauver notre équipe des travaux fastidieux
Si vous utilisez du TDD pur, cela vous oblige à vous arrêter un instant et à vous demander si le fait d'avoir une propriété publique auto est même la meilleure chose à faire (indice: ce n'est souvent pas le cas!)
Ne préféreriez-vous pas avoir un test de régression initial afin que, lorsque le FNG effectue quelque chose comme ceci:
//24-SEP-2013::FNG - put backing field for ConnectionString as we're now doing constructor injection of it
public string ConnectionString
{
{get { return _connectionString; } }
{set {_connectionString="foo"; } }//FNG: I'll change this later on, I'm in a hurry
}
///snip
public MyDBClass(string connectionString)
{
ConnectionString=connectionString;
}
Vous instantanément savez qu'ils ont cassé quelque chose?
Si ce qui précède semble être conçu pour une propriété de chaîne simple, j'ai personnellement vu une situation où une propriété automatique était refactorisée par quelqu'un qui pensait être si intelligent et qui voulait le changer d'un membre d'instance à un wrapper autour d'un membre statique de la classe. (représentant une connexion de base de données au fur et à mesure, les conséquences du changement ne sont pas importantes).
Bien sûr, cette même personne très intelligente complètement oublié pour dire à quelqu'un d'autre qu'il lui fallait appeler une fonction magique pour initialiser ce membre statique.
Cela a entraîné la compilation de l'application et son envoi à un client, après quoi elle a rapidement échoué. Ce n'est pas une grosse affaire, mais cela a coûté plusieurs heures de support à == l'argent .... Ce muppet, c'était moi!
EDIT: comme dans diverses conversations sur ce fil, je voulais souligner qu'un test pour une propriété en lecture-écriture est ridiculement simple:
[TestMethod]
public void PropertyFoo_StoresCorrectly()
{
var sut = new MyClass();
sut.Foo = "hello";
Assert.AreEqual("hello", sut.Foo, "Oops...");
}
edit: Et vous pouvez même le faire en une seule ligne selon Mark Seeman/ Autofixture
Je soutiendrais que si vous trouvez que vous avez un nombre de propriétés publiques tel que l’écriture de 3 lignes comme celle ci-dessus devienne une corvée pour chacune d’elles, vous devriez alors remettre en question votre conception; Si vous utilisez un autre test pour indiquer un problème avec cette propriété,
edit (encore!): Comme indiqué dans les commentaires, et à juste titre, des éléments tels que les modèles DTO générés et similaires sont probablement des exceptions à ce qui précède, car ils ne sont que de vieux seaux stupides pour déplacer des données ailleurs, plus depuis qu'un outil les a créés , il est généralement inutile de les tester.
/MODIFIER
En fin de compte, "ça dépend" est probablement la vraie réponse, à condition toutefois que la meilleure solution "par défaut" soit l'approche "toujours fais-le", avec des exceptions à celle prise de manière éclairée, au cas par cas.
Généralement non. Un test unitaire doit être utilisé pour tester la fonctionnalité d'une unité. Vous devez utiliser des méthodes de test unitaires sur une classe et non des propriétés automatiques individuelles (à moins que vous ne surchargiez le getter ou le setter avec un comportement personnalisé).
Vous savez que l'affectation d'une valeur de chaîne à une propriété de chaîne automatique fonctionnera si vous obtenez la syntaxe et la valeur de définition correctes, car elles font partie de la spécification de langue. Si vous ne le faites pas, vous obtiendrez une erreur d'exécution pour signaler votre faille.
Les tests unitaires doivent être conçus pour rechercher les erreurs logiques dans le code plutôt que quelque chose que le compilateur attraperait de toute façon.
EDIT: Selon ma conversation avec l'auteur de la réponse acceptée pour cette question, je voudrais ajouter ce qui suit.
Je peux comprendre que les puristes de TDD diraient que vous devez tester les propriétés automatiques. Mais en tant que développeur d’applications d’affaires, j’ai besoin de peser raisonnablement le temps que je pourrais consacrer à l’écriture et à la réalisation de tests de code «trivial», tels que des propriétés automatiques, par rapport au temps qu'il faudrait raisonnablement pour résoudre un problème pouvant découler pas de test. D'après l'expérience personnelle, la plupart des bogues générés par la modification d'un code trivial sont faciles à résoudre 99% du temps. Pour cette raison, je dirais que les avantages de la fonctionnalité de spécification non langagière testée à l’unité par les tests unitaires dépassent les inconvénients.
Si vous travaillez dans un environnement professionnel au rythme rapide qui utilise une approche TDD, une partie du flux de travail de cette équipe doit consister à ne tester que le code qui doit être testé, essentiellement tout code personnalisé. Si quelqu'un entre dans votre classe et modifie le comportement d'une propriété automatique, il lui incombe de configurer un test unitaire à ce moment-là.
Adhérez-vous à des pratiques strictes de TDD ou pas?
Si oui, alors vous absolument devriez écrire des tests sur les getters et les setters publics, sinon, comment saurez-vous si vous les avez correctement implémentés?
Si non, vous devriez probablement encore écrire les tests. Bien que l’implémentation soit aujourd’hui triviale, il n’est pas garanti de le rester, et sans test couvrant les fonctionnalités d’une simple opération get/set, lorsqu’une modification ultérieure de l’implémentation annule une invariante de "la propriété Foo avec une valeur Bar a pour résultat le getter de la propriété Foo renvoyant la valeur Bar "les tests unitaires continueront de réussir. Le test lui-même est est également implémenté de manière triviale, tout en protégeant contre les changements futurs.
Je devrais dire non. Si cela ne fonctionne pas, vous avez de plus gros problèmes. Je sais que non. Certains diront maintenant que le code seul suffirait à faire échouer le test si la propriété était supprimée, par exemple. Mais je mettrais de l'argent sur le fait que si la propriété était supprimée, le code de test unitaire serait supprimé dans le refactor, donc cela n'aurait aucune importance.
La façon dont je vois les choses, c’est que le nombre de tests unitaires (ou de tests en général) dépend du degré de confiance que le code fonctionne comme prévu et des chances de rupture dans le futur.
Si vous avez une confiance moindre en la rupture de code (peut-être en raison de la sous-traitance du code et du coût élevé du contrôle ligne par ligne), alors les propriétés de test unitaire sont appropriées.
Une fois que vous pouvez faire est d’écrire une classe auxiliaire qui peut passer en revue toutes les propriétés get/set d’une classe afin de vérifier qu’elles se comportent toujours comme prévu.
Selon le livre L'art du test unitaire Avec des exemples dans .NET , un test unitaire ne couvre aucun type de code, il se concentre sur code logique. Alors, qu'est-ce que code logique?
Le code logique est tout morceau de code contenant une sorte de logique, aussi petit qu'il puisse être. C'est un code logique s'il comporte un ou plusieurs des éléments suivants instructions de cas, calculs, ou tout autre type de code décisionnel.
Un simple getter/setter encapsule-t-il une quelconque logique? La réponse est:
Les propriétés (getters/setters en Java) sont de bons exemples de code qui ne contient généralement pas de logique et ne nécessite donc pas de test. Mais faites attention: une fois que vous aurez ajouté un chèque à l’intérieur de la propriété, vous voudrez assurez-vous que cette logique est testée.
Sauf si les propriétés exécutent une autre sorte de logique, alors non.
Oui, c'est comme si l'unité testait la langue. Sinon, il serait totalement inutile de tester des propriétés simples implémentées automatiquement.
Ma réponse, qui provient du point de vue de l'ancien responsable du test et actuellement responsable du développement (responsable de la livraison du logiciel en temps et en qualité) Je vois des gens parler de pragmatisme. Le pragmatisme n'est pas un bon conseiller car il peut être associé à la paresse et/ou à la pression du temps. Cela peut vous conduire sur le mauvais chemin. Si vous parlez de pragmatisme, vous devez veiller à maintenir vos intentions sur la voie du professionnalisme et du bon sens. Il faut de l'humilité pour accepter les réponses, car elles ne sont peut-être pas ce que vous voulez entendre.
De mon point de vue, ce qui est important sont les suivants:
Dans l’ensemble, il n’ya pas de bonne réponse. Juste d'autres questions auxquelles vous devez répondre pour obtenir ce point temporaire où vous êtes capable de décider si c'est nécessaire ou non.