Comment savez-vous quoi tester lors de l'écriture de tests unitaires? [fermé]

StackOverflow https://stackoverflow.com/questions/62625

  •  09-06-2019
  •  | 
  •  

Question

En C #, il me faut une classe appelée Utilisateur , qui comporte un nom d'utilisateur, un mot de passe, un indicateur actif, un prénom, un nom, un nom complet, etc.

Il devrait exister des méthodes pour authentifier et enregistrer un utilisateur. Dois-je simplement écrire un test pour les méthodes? Et dois-je même avoir à me soucier de tester les propriétés car elles sont les getter et les setters de .Net?

Était-ce utile?

La solution

Ma question a également suscité de nombreuses réponses intéressantes: " TDD initial - Défis? Solutions? Recommandations? "

Puis-je également recommander de consulter mon article de blog (en partie inspiré par ma question), j'ai de bons retours à ce sujet. À savoir:

  

Je ne sais pas par où commencer?

     
      
  • Recommencez. Ne pensez à écrire des tests que lorsque vous écrivez de nouvelles   code. Cela peut être re-travail de vieux   code, ou une toute nouvelle fonctionnalité.
  •   
  • Commencez simplement. Ne vous précipitez pas et n'essayez pas de vous prendre la tête   un cadre de test en plus d'être   TDD-esque. Debug.Assert fonctionne bien.   Utilisez-le comme point de départ. Il ne faut pas   jouer avec votre projet ou créer   dépendances.
  •   
  • Commencez positif. Vous essayez d'améliorer votre métier, vous vous sentez bien   il. J'ai vu beaucoup de développeurs   là-bas qui sont heureux de stagner   et ne pas essayer de nouvelles choses pour mieux   se. Tu fais le bien   chose, rappelez-vous ceci et cela vous aidera   vous empêcher d'abandonner.
  •   
  • Commencez prêt pour un défi. Il est assez difficile de commencer à entrer dans   essai. Attendez-vous à un défi, mais   rappelez-vous & # 8211; les défis peuvent être surmontés.
  •   
     

Ne testez que ce que vous attendez

     

J'ai eu de vrais problèmes quand j'ai commencé   commencé parce que j'étais constamment assis   il essaie de comprendre tous les   problème possible qui pourrait se produire et   puis essayer de le tester et de le réparer.   C'est un moyen rapide pour un mal de tête.   Le test devrait être un vrai YAGNI   processus. Si vous savez il y a un   problème, puis écrivez un test pour cela.   Sinon, ne vous embêtez pas.

     

Ne tester qu'une chose

     

Chaque cas de test ne doit jamais tester   une chose. Si jamais tu te retrouves   mettre & # 8220; et & # 8221; dans le nom du cas de test,   vous faites quelque chose de mal.

J'espère que cela signifie que nous pouvons passer de "getters and setters" :)

Autres conseils

Testez votre code, pas la langue.

Un test unitaire du type:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

n'est utile que si vous écrivez un compilateur et qu'il y a une chance que votre méthode instanceof ne fonctionne pas.

Ne testez pas les éléments que vous pouvez utiliser dans le langage à appliquer. Dans votre cas, je me concentrerais sur vos méthodes d’authentification et d’enregistrement - et j’écrirais des tests garantissant qu’elles pouvaient gérer les valeurs NULL dans n’importe lequel de ces champs ou dans leur totalité.

Cela m'a permis de passer aux tests unitaires et m'a rendu très heureux

Nous venons juste de commencer à faire des tests unitaires. Pendant longtemps, j'ai su qu'il serait bon de commencer à le faire, mais je ne savais pas comment commencer ni, surtout, ce qu'il fallait tester.

Ensuite, nous avons dû réécrire un élément de code important dans notre programme de comptabilité. Cette partie était très complexe car elle impliquait beaucoup de scénarios différents. La partie dont je parle est une méthode pour payer les factures de vente et / ou d’achat déjà entrées dans le système comptable.

Je ne savais tout simplement pas comment commencer à le coder, car il y avait tellement d'options de paiement différentes. Une facture pourrait s’élever à 100 USD, mais le client n’a transféré que 99 USD. Vous avez peut-être envoyé des factures de vente à un client, mais vous avez également acheté auprès de ce client. Donc, vous l'avez vendu 300 $ mais vous avez acheté 100 $. Vous pouvez vous attendre à ce que votre client vous paie 200 $ pour régler le solde. Et si vous vendiez 500 USD mais que le client ne vous paie que 250 USD?

J'ai donc eu un problème très complexe à résoudre avec de nombreuses possibilités qu'un scénario fonctionne parfaitement mais se trompe avec un autre type de combinaison invocie / paiement.

C’est là que les tests unitaires sont venus à la rescousse.

J'ai commencé à écrire (dans le code de test) une méthode pour créer une liste de factures, à la fois pour les ventes et les achats. Ensuite, j'ai écrit une deuxième méthode pour créer le paiement réel. Normalement, un utilisateur entre ces informations via une interface utilisateur.

Ensuite, j'ai créé le premier TestMethod, testant un paiement très simple d'une facture unique sans aucune réduction de paiement. Toutes les actions du système se produiraient lorsqu'un paiement bancaire serait enregistré dans la base de données. Comme vous pouvez le voir, j'ai créé une facture, créé un paiement (une transaction bancaire) et enregistré la transaction sur le disque. Dans mes affirmations, je mets ce qui devrait être les bons numéros se retrouvant dans la transaction bancaire et dans la facture liée. Je vérifie le nombre de paiements, le montant des paiements, le montant de la remise et le solde de la facture après la transaction.

Après l'exécution du test, j'allais dans la base de données et revérifiais si ce que j'espérais y était.

Après avoir rédigé le test, j'ai commencé à coder le mode de paiement (élément de la classe BankHeader). Dans le codage, je ne me suis préoccupé que du code pour réussir le premier test. Je n'ai pas encore pensé aux autres scénarios, plus complexes.

J'ai exécuté le premier test, corrigé un petit bug jusqu'à la réussite de mon test.

Ensuite, j'ai commencé à écrire le deuxième test, cette fois-ci avec une réduction de paiement. Après avoir rédigé le test, j'ai modifié le mode de paiement afin de prendre en charge les remises.

Lors du test de l'exactitude avec une réduction de paiement, j'ai également testé le paiement simple. Les deux tests devraient bien sûr réussir.

J'ai ensuite abordé des scénarios plus complexes.

1) Pensez à un nouveau scénario

2) Rédigez un test pour ce scénario

3) Exécutez ce test unique pour voir s'il réussirait

4) Sinon, je déboguerais et modifierais le code jusqu'à ce qu'il passe.

5) Tout en modifiant le code, j'ai continué à exécuter tous les tests

C’est ainsi que j’ai réussi à créer mon mode de paiement très complexe. Sans tests unitaires, je ne savais pas comment commencer à coder, le problème semblait accablant. Grâce aux tests, je pouvais commencer avec une méthode simple et l’étendre étape par étape avec l’assurance que les scénarios les plus simples fonctionneraient toujours.

Je suis sûr que les tests unitaires m'ont permis de gagner quelques jours (ou plusieurs semaines) de codage et de garantir plus ou moins l'exactitude de ma méthode.

Si par la suite je pense à un nouveau scénario, je peux simplement l'ajouter aux tests pour voir s'il fonctionne ou non. Sinon, je peux modifier le code tout en m'assurant que les autres scénarios fonctionnent toujours correctement. Cela économisera des jours et des jours dans la phase de maintenance et de correction des bugs.

Oui, même le code testé peut toujours comporter des bogues si un utilisateur fait des choses auxquelles vous n'avez pas pensé ou l'a empêché de le faire

Vous trouverez ci-dessous quelques-uns des tests que j'ai créés pour tester mon mode de paiement.

public class TestPayments
{
    InvoiceDiaryHeader invoiceHeader = null;
    InvoiceDiaryDetail invoiceDetail = null;
    BankCashDiaryHeader bankHeader = null;
    BankCashDiaryDetail bankDetail = null;



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date)
    {
        ......
        ......
    }

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount)
    {
       ......
       ......
       ......
    }


    [TestMethod]
    public void TestSingleSalesPaymentNoDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 1, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSingleSalesPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 2, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    [ExpectedException(typeof(ApplicationException))]
    public void TestDuplicateInvoiceNumber()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("100", true, 2, "01-09-2008"));
        list.Add(CreateSales("200", true, 2, "01-09-2008"));

        bankHeader = CreateMultiplePayments(list, 3, 300, 0);
        bankHeader.Save();
        Assert.Fail("expected an ApplicationException");
    }

    [TestMethod]
    public void TestMultipleSalesPaymentWithPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 11, "01-09-2008"));
        list.Add(CreateSales("400", true, 12, "02-09-2008"));
        list.Add(CreateSales("600", true, 13, "03-09-2008"));
        list.Add(CreateSales("25,40", true, 14, "04-09-2008"));

        bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount);
        Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount);

        Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount);

        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSettlement()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales
        list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase

        bankHeader = CreateMultiplePayments(list, 22, 200, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
    }

S'ils sont vraiment triviaux, alors ne vous inquiétez pas des tests. Par exemple, s’ils sont mis en œuvre de cette manière;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Si, par contre, vous faites quelque chose d'intelligent (comme chiffrer et déchiffrer le mot de passe dans le getter / setter), faites-en un test.

La règle est que vous devez tester chaque élément de logique que vous écrivez. Si vous avez implémenté des fonctionnalités spécifiques dans les getters et les setters, je pense qu’elles valent la peine d’être testées. S'ils n'affectent que des valeurs à certains champs privés, ne vous inquiétez pas.

Cette question semble être une question de savoir où tracer la ligne en ce qui concerne les méthodes testées et celles qui ne le sont pas.

Les personnes qui définissent et getters pour l’affectation de valeur ont été créées dans un souci de cohérence et de croissance future, et prévoient qu’un jour ou l’autre le décideur / getter pourrait évoluer vers des opérations plus complexes. Il serait logique de mettre en place des tests unitaires de ces méthodes, également dans un souci de cohérence et de croissance future.

L'objectif principal est la fiabilité du code, en particulier lors de modifications visant à ajouter des fonctionnalités supplémentaires. Je ne suis au courant de personne qui se soit fait virer pour avoir inclus des setters / getters dans la méthodologie de test, mais je suis certain qu'il existe des personnes qui auraient souhaité avoir testé des méthodes dont elles étaient au courant ou dont elles se souviennent étaient simples, mais ce n'était pas le cas plus le cas.

Peut-être un autre membre de l'équipe a-t-il développé les méthodes set / get pour inclure la logique qui doit maintenant être testée mais n'a pas ensuite créé les tests. Mais maintenant, votre code appelle ces méthodes et vous ne savez pas qu'elles ont changé et nécessitent des tests approfondis. Les tests que vous effectuez en développement et en assurance qualité ne déclenchent pas le problème, mais les données commerciales réelles du premier jour de publication ne déclenche le.

Les deux coéquipiers vont maintenant débattre de la personne qui a lâché la balle et qui n'a pas réussi à mettre les tests unitaires lorsque l'ensemble / se métamorphose afin d'inclure une logique qui peut échouer mais qui n'est pas couverte par un test unitaire. Le coéquipier qui a initialement écrit le set / gets aura plus de facilité à sortir de ce nettoyage si les tests ont été mis en œuvre dès le premier jour sur le set / gets simple.

Mon avis est que quelques minutes de " gaspillé " Le temps consacré à TOUTES les méthodes avec des tests unitaires, même les plus triviaux, pourrait vous épargner des jours de mal de tête, de perte d'argent / de réputation de l'entreprise et de perte du travail de quelqu'un.

Et le fait que vous ayez associé des méthodes triviales à des tests unitaires peut être perçu par ce coéquipier junior qui modifie les méthodes triviales en méthodes non triviales et les incite à mettre à jour le test. Désormais, personne n’a de problèmes le défaut était empêché d'atteindre la production.

La façon dont nous codons et la discipline qui peut être vue à partir de notre code peuvent aider les autres.

Une autre réponse canonique. Ceci, je crois, de Ron Jeffries:

  

Ne testez que le code que vous souhaitez utiliser.

Tester le code standard est une perte de temps, mais comme le dit Slavo, si vous ajoutez un effet secondaire à vos getters / setters, vous devez écrire un test pour accompagner cette fonctionnalité.

Si vous effectuez un développement piloté par des tests, vous devez d’abord rédiger le contrat (par exemple, une interface), puis rédiger le (s) test (s) permettant d’exercer cette interface qui documente les résultats / comportements attendus. Ensuite écrivez vos méthodes elles-mêmes, sans toucher au code de vos tests unitaires. Enfin, récupérez un outil de couverture de code et assurez-vous que vos tests suivent toutes les pistes logiques de votre code.

Les codes vraiment triviaux, tels que les accesseurs et les préposés qui n'ont pas de comportement supplémentaire par rapport à la définition d'un champ privé, sont excessifs à tester. Dans la version 3.0, C # a même un sucre syntaxique dans lequel le compilateur s’occupe du champ privé afin que vous n’ayez pas à le programmer.

J'écris habituellement beaucoup de tests très simples pour vérifier le comportement que j'attends de mes cours. Même si c'est simple, comme ajouter deux nombres. Je change beaucoup entre écrire un simple test et écrire des lignes de code. La raison en est que je peux alors changer de code sans avoir peur de casser des choses auxquelles je ne pensais pas.

Vous devriez tout tester. À l'heure actuelle, vous avez des accesseurs et des passeurs, mais un jour, vous pourriez les modifier quelque peu, par exemple pour effectuer une validation ou autre chose. Les tests que vous écrivez aujourd'hui seront utilisés demain pour s'assurer que tout continue à fonctionner normalement. Lorsque vous écrivez le test, vous devriez oublier les considérations telles que "pour le moment, c'est trivial". Dans un contexte agile ou axé sur les tests, vous devez tester en supposant une refactorisation future. Avez-vous également essayé d’ajouter des valeurs vraiment étranges, telles que des chaînes extrêmement longues ou d’autres méthodes "mauvaises"? contenu? Eh bien, vous devriez ... ne jamais présumer à quel point votre code peut être utilisé de manière abusive à l'avenir.

En général, je trouve qu’écrire des tests utilisateur volumineux est épuisant. De l’autre côté, même si cela vous donne toujours des informations précieuses sur le fonctionnement de votre application et vous permet d’éviter les suppositions simples (et fausses) (comme: le nom d’utilisateur sera toujours inférieur à 1000 caractères).

Pour les modules simples pouvant se retrouver dans une boîte à outils ou dans un type de projet open source, vous devez tester autant que possible, y compris les getters et les setters triviaux. Ce que vous voulez garder à l'esprit, c'est que générer un test unitaire lors de l'écriture d'un module particulier est assez simple et direct. L'ajout de getters et de setters est un code minimal et peut être manipulé sans trop y penser. Cependant, une fois que votre code est placé dans un système plus grand, cet effort supplémentaire peut vous protéger contre les modifications du système sous-jacent, telles que les modifications de type dans une classe de base. Tester tout est le meilleur moyen d'avoir une régression complète.

Cela ne fait pas de mal d’écrire des tests unitaires pour vos accesseurs. À l’heure actuelle, ils ne font peut-être que des recherches sur le terrain, mais à l’avenir, vous aurez peut-être une logique de validation ou des dépendances entre propriétés qui devront être testées. Il est plus facile de l'écrire maintenant pendant que vous y réfléchissez puis de vous souvenir de l'adapter ultérieurement si jamais cela arrivait.

En général, lorsqu'une méthode n'est définie que pour certaines valeurs, testez les valeurs sur et sur la limite de ce qui est acceptable. En d’autres termes, assurez-vous que votre méthode fait ce qu’elle est supposée faire, mais rien de plus . Ceci est important, car lorsque vous allez échouer, vous voulez échouer tôt.

Dans les hiérarchies d'héritage, veillez à vérifier la conformité de LSP .

Tester les getters et les setters par défaut ne me semble pas très utile, sauf si vous envisagez d'effectuer une validation ultérieurement.

Si je comprends bien les tests unitaires dans le contexte du développement agile, Mike, oui, vous devez tester les accesseurs et les passeurs (en supposant qu’ils soient visibles publiquement). Le concept de test unitaire consiste à tester l'unité logicielle, qui est une classe dans ce cas, en tant que black boîte . Les accesseurs et les setters étant visibles de l'extérieur, vous devez les tester avec Authentifier et enregistrer.

Si les méthodes Authentifier et Enregistrer utilisent les propriétés, vos tests toucheront indirectement les propriétés. Tant que les propriétés fournissent uniquement un accès aux données, des tests explicites ne devraient pas être nécessaires (à moins que vous ne souhaitiez une couverture à 100%).

Je voudrais tester vos getters et setters. Selon l'auteur du code, certaines personnes modifient la signification des méthodes getter / setter. J'ai vu l'initialisation de variables et d'autres validations dans le cadre des méthodes getter. Afin de tester ce genre de chose, vous voudriez que les tests unitaires couvrent explicitement ce code.

Personnellement, je "testerais tout ce qui peut casser" et un simple getter (ou même de meilleures propriétés automatiques) ne se cassera pas. Je n'ai jamais fait échouer une simple déclaration de retour et, par conséquent, je n'ai jamais testé pour eux. Si les getters ont des calculs en leur sein ou une autre forme d’énoncé, j’ajouterais certainement des tests pour eux.

Personnellement, j'utilise Moq en tant que structure d'objet fictif, puis je vérifie que mon objet appelle le les objets environnants comme il se doit.

Vous devez couvrir l'exécution de chaque méthode de la classe avec UT et vérifier la valeur de retour de la méthode. Cela inclut les getters et les setters, en particulier si les membres (propriétés) sont des classes complexes, ce qui nécessite une importante allocation de mémoire lors de leur initialisation. Appelez le passeur avec une très grosse chaîne par exemple (ou quelque chose avec des symboles grecs) et vérifiez que le résultat est correct (non tronqué, le codage est bon e.t.c.)

Dans le cas d'entiers simples, cela s'applique également - qu'advient-il si vous passez long au lieu d'entier? C'est la raison pour laquelle vous écrivez UT pour:)

Je ne testerais pas le paramétrage réel des propriétés. Je serais plus préoccupé par la façon dont ces propriétés sont peuplées par le consommateur et par quoi elles sont peuplées. Avec tout test, vous devez peser les risques avec le temps / coût des tests.

Vous devez tester "chaque bloc de code non trivial". en utilisant autant que possible les tests unitaires.

Si vos propriétés sont triviales et qu'il est peu probable que quelqu'un y introduise un bogue, il est prudent de ne pas les tester à l'unité.

Vos méthodes Authenticate () et Save () semblent être de bons candidats pour les tests.

Idéalement, vous auriez fait vos tests unitaires en écrivant le cours. C’est ce que vous êtes censé faire lorsque vous utilisez le développement piloté par les tests. Vous ajoutez les tests au fur et à mesure que vous implémentez chaque point de fonction, en vous assurant de couvrir également les cas-limites avec test.

Écrire les tests par la suite est beaucoup plus pénible, mais faisable.

Voici ce que je ferais dans votre position:

  1. Rédigez un ensemble de tests de base qui testent la fonction principale.
  2. Obtenez NCover et exécutez-le sur vos tests. Votre couverture de test sera probablement d'environ 50% à ce stade.
  3. Continuez à ajouter des tests couvrant vos cas extrêmes jusqu'à une couverture d'environ 80% à 90%

Cela devrait vous donner un bon ensemble de tests unitaires qui serviront de bon tampon contre les régressions.

Le seul problème avec cette approche est que le code doit être conçu pour pouvoir être testé de cette manière. Si vous avez commis des erreurs de couplage très tôt, vous ne pourrez pas obtenir une couverture élevée très facilement.

C'est pourquoi il est vraiment important d'écrire les tests avant d'écrire le code. Cela vous oblige à écrire du code faiblement couplé.

Ne testez pas le code de fonctionnement manifeste (passe-partout). Donc, si vos setters et getters sont juste " propertyvalue = value " et " return propertyvalue " cela n'a aucun sens de le tester.

Même obtenir / définir peut avoir des conséquences étranges, en fonction de la manière dont elles ont été mises en œuvre. Elles doivent donc être traitées comme des méthodes.

Chaque test de ceux-ci devra spécifier des ensembles de paramètres pour les propriétés, en définissant des propriétés acceptables et inacceptables pour garantir que les appels renvoient / échouent de la manière attendue.

Vous devez également connaître les pièges de sécurité, à titre d'exemple d'injection SQL, et les tester.

Alors oui, vous devez vous soucier de tester les propriétés.

Je pense que c'est idiot de tester Getters & amp; les setters quand ils ne font qu’une opération simple. Personnellement, je n’écris pas de tests unitaires complexes pour couvrir tous les types d’utilisation. J'essaie d'écrire suffisamment de tests pour m'assurer que j'ai géré le comportement d'exécution normal et autant de cas d'erreur que je peux penser. J'écrirai plus de tests unitaires en réponse à des rapports de bugs. J'utilise des tests unitaires pour vérifier que le code répond aux exigences et faciliter les modifications futures. Je me sens beaucoup plus disposé à changer de code quand je sais que si je casse quelque chose, le test échouera.

Je voudrais écrire un test pour tout ce pour quoi vous écrivez du code qui peut être testé en dehors de l'interface graphique.

En règle générale, toute logique que j'écris et qui possède une logique métier que je place dans un autre niveau ou une couche de logique métier.

Il est facile de faire des tests pour tout ce qui fait quelque chose.

Commencez par rédiger un test unitaire pour chaque méthode publique de votre "couche de logique métier".

Si j'avais un cours comme celui-ci:

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

La première chose à faire avant d'écrire un code sachant que j'avais ces actions à effectuer était de commencer à écrire des tests unitaires.

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

Ecrivez vos tests pour valider le code que vous avez écrit pour faire quelque chose. Si vous parcourez un ensemble de choses et que vous changez quelque chose à chacune d’elles, écrivez un test qui fait la même chose et affirmez que cela s’est réellement passé.

Il existe de nombreuses autres approches que vous pouvez adopter, à savoir le développement dirigé par le comportement (BDD), qui sont plus impliquées et qui ne sont pas un excellent point de départ pour vos compétences en tests unitaires.

La morale de l’histoire est donc la suivante: testez tout ce qui vous préoccupe, laissez les tests unitaires tester des objets spécifiques de petite taille. De nombreux tests sont bons.

Conservez votre logique métier en dehors de la couche Interface utilisateur afin de pouvoir facilement écrire des tests pour ces tests, et vous serez performant.

Je recommande TestDriven.Net ou ReSharper s’intégrant facilement dans Visual Studio.

Eh bien, si vous pensez que ça peut casser, écrivez un test pour cela. Habituellement, je ne teste pas le getter / getter, mais disons que vous en créez un pour User.Name, qui concatène le nom et le prénom, j'écrirais un test afin que si quelqu'un modifie l'ordre pour le nom et le prénom, au moins il le saurait il a changé quelque chose qui a été testé.

La réponse canonique est "testez tout ce qui peut éventuellement se casser". Si vous êtes certain que les propriétés ne casseront pas, ne les testez pas.

Et une fois que quelque chose s’est brisé (vous trouvez un bogue), cela signifie évidemment que vous devez le tester. Ecrivez un test pour reproduire le bogue, observez son échec, puis corrigez le bogue, puis regardez le test passer.

Je vous recommanderais d’écrire plusieurs tests pour vos méthodes d’authentification et d’enregistrement. En plus du cas de réussite (où tous les paramètres sont fournis, tout est correctement orthographié, etc.), il est bon de disposer de tests pour divers cas d'échec (paramètres incorrects ou manquants, connexions à la base de données non disponibles, le cas échéant, etc.). Je recommande Test d'unité pragmatique en C # avec NUnit comme référence.

Comme d’autres l’ont déjà dit, les tests unitaires pour les accesseurs et les setters sont excessifs, sauf s’il existe une logique conditionnelle entre vos accesseurs et les setters.

Bien qu'il soit possible de deviner correctement où votre code doit être testé, je pense généralement que vous avez besoin de métriques pour sauvegarder cette estimation. À mon avis, les tests unitaires vont de pair avec les mesures de couverture de code.

Code avec beaucoup de tests mais une petite couverture n'a pas été bien testée. Cela dit, un code avec une couverture de 100% mais ne testant pas les limites et les cas d'erreur n'est également pas génial.

Vous voulez un équilibre entre une couverture élevée (minimum 90%) et des données d'entrée variables.

N'oubliez pas de tester "Garbage in"!

En outre, un test unitaire n’est pas un test unitaire sauf s’il vérifie la présence d’un échec. Les tests unitaires sans assertions ou marqués avec des exceptions connues vérifieront simplement que le code ne meurt pas lorsqu'il est exécuté!

Vous devez concevoir vos tests de manière à ce qu'ils signalent toujours les échecs ou les données inattendues / indésirables!

Cela améliore notre code ... point final!

Les développeurs de logiciels oublient que nos actions ont pour but de développer des tests. Si un test unitaire est écrit alors que le code de production est déjà en place, la valeur du test diminue considérablement (mais n'est pas complètement perdue).

Dans le véritable esprit des tests unitaires, ces tests ne sont pas principalement destinés à "tester". plus de notre code; ou pour obtenir une couverture de code supérieure de 90% à 100%. Ce sont tous des avantages marginaux de passer les tests en premier. Le gros avantage est que notre code de production finit par être écrit beaucoup mieux en raison du processus naturel du TDD.

Pour aider à mieux communiquer cette idée, les éléments suivants peuvent être utiles à la lecture:

Théorie erronée des tests unitaires < br> Développement de logiciels ciblé

Si nous estimons que le fait d'écrire plus de tests unitaires est ce qui nous aide à obtenir un produit de meilleure qualité, nous risquons de souffrir d'un Culte Cargo du développement piloté par les tests.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top