web-dev-qa-db-fra.com

Tests unitaires des méthodes vides?

Quelle est la meilleure façon de tester à l'unité une méthode qui ne retourne rien? Plus précisément en c #.

Ce que j’essaie vraiment de tester est une méthode qui prend un fichier journal et l’analyse pour des chaînes spécifiques. Les chaînes sont ensuite insérées dans une base de données. Rien de ce qui n'a été fait auparavant mais TRÈS nouveau sur TDD, je me demande s'il est possible de tester ceci ou si c'est quelque chose qui n'a pas vraiment été testé.

150
jdiaz

Si une méthode ne retourne rien, c'est l'une des méthodes suivantes.

  • impératif - Vous demandez à l'objet de faire quelque chose pour lui-même. Par exemple, changez d'état (sans attendre de confirmation .. il est supposé qu'il le sera terminé)
  • informatif - signalez simplement à quelqu'un que quelque chose s'est passé (sans attendre d'action ou de réponse).

Méthodes impératives - vous pouvez vérifier si la tâche a bien été effectuée. Vérifiez si le changement d'état a réellement eu lieu. par exemple.

void DeductFromBalance( dAmount ) 

peut être testé en vérifiant si le solde après ce message est bien inférieur à la valeur initiale par dAmount

Les méthodes d'information - sont rares en tant que membre de l'interface publique de l'objet ... donc normalement pas testées par unité. Cependant, si vous devez le faire, vous pouvez vérifier si le traitement à effectuer sur une notification a bien lieu. par exemple.

void OnAccountDebit( dAmount )  // emails account holder with info

peut être testé en vérifiant si l'e-mail est envoyé

Postez plus de détails sur votre méthode et les gens seront en mesure de mieux vous répondre.
Update : Votre méthode fait 2 choses. En fait, je l'aurais scindé en deux méthodes pouvant maintenant être testées indépendamment.

string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );

String [] peut être facilement vérifié en fournissant à la première méthode un fichier fictif et les chaînes attendues. La seconde est un peu délicate. Vous pouvez utiliser un Mock (Google ou search stackoverflow sur des frameworks moqueurs) pour imiter la base de données ou appuyer sur la base de données et vérifier si les chaînes ont été insérées au bon endroit. Vérifiez ce fil pour quelques bons livres ... Je recommanderais Pragmatic Unit Testing si vous êtes en crise.
Dans le code, il serait utilisé comme

InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
139
Gishu

Testez ses effets secondaires. Ceci comprend:

  • Est-ce qu'il jette des exceptions? (Si c'est le cas, vérifiez-le. Dans le cas contraire, essayez quelques cas de figure qui pourraient l'être si vous ne faites pas attention - les arguments nuls étant la chose la plus évidente.)
  • Est-ce qu'il joue bien avec ses paramètres? (S'ils sont mutables, est-ce que ça les mute quand ça ne devrait pas et vice versa?)
  • Cela at-il un effet correct sur l’état de l’objet/type sur lequel vous l’appelez?

Bien sûr, il y a une limite à comment beaucoup vous pouvez tester. Vous ne pouvez généralement pas tester avec toutes les entrées possibles, par exemple. Testez de manière pragmatique - suffisamment pour vous assurer que votre code est conçu de manière appropriée et correctement implémenté, et suffisamment pour servir de documentation supplémentaire indiquant les attentes d'un appelant.

59
Jon Skeet

Comme toujours: testez ce que la méthode est supposée faire!

Devrait-il changer d’état global (euh, odeur de code!) Quelque part?

Devrait-il appeler une interface?

Devrait-il lancer une exception lorsqu'il est appelé avec les mauvais paramètres?

Ne devrait-il pas lancer une exception lorsqu'il est appelé avec les bons paramètres?

Devrait-il ...?

28
David Schmitt

Les types de renvois/sous-programmes sont des anciennes actualités. Je n'ai pas fait de type Void (sauf si j'étais extrêmement paresseux) depuis 8 ans (à partir du moment de cette réponse, donc un peu avant que cette question ne soit posée).

Au lieu d'une méthode comme:

public void SendEmailToCustomer()

Créez une méthode qui suit le paradigme int.TryParse () de Microsoft:

public bool TrySendEmailToCustomer()

Peut-être n’a-t-il aucune information que votre méthode doit renvoyer pour utilisation à long terme, mais le retour de l’état de la méthode après qu’il effectue son travail est une utilisation énorme pour l’appelant.

De plus, bool n'est pas le seul type d'état. Il existe un certain nombre de fois où un sous-programme précédemment créé peut en réalité renvoyer trois états différents ou plus (Bon, Normal, Mauvais, etc.). Dans ces cas, vous utiliseriez simplement

public StateEnum TrySendEmailToCustomer()

Cependant, alors que Try-Paradigm répond quelque peu à cette question sur la façon de tester un retour à vide, il existe également d'autres considérations. Par exemple, pendant/après un cycle "TDD", vous ferez un "refactoring" et remarquerez que vous faites deux choses avec votre méthode ... brisant ainsi le "principe de responsabilité unique". Donc, cela devrait être pris en charge en premier. Deuxièmement, vous avez peut-être identifié une dépendance ... vous touchez des données "persistantes".

Si vous effectuez les opérations d'accès aux données dans la méthode en question, vous devez procéder à une refactorisation dans une architecture à plusieurs niveaux ou à plusieurs niveaux. Mais nous pouvons supposer que lorsque vous dites "Les chaînes sont ensuite insérées dans une base de données", vous voulez en fait dire que vous appelez une couche de logique métier ou quelque chose du genre. Ya, on va supposer ça.

Lorsque votre objet est instancié, vous comprenez maintenant que votre objet a des dépendances. C'est à ce moment que vous devez décider si vous allez effectuer une injection de dépendance sur l'objet ou sur la méthode. Cela signifie que votre constructeur ou la méthode en question a besoin d'un nouveau paramètre:

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)

Maintenant que vous pouvez accepter une interface de votre objet métier/données, vous pouvez la simuler pendant les tests unitaires sans craindre de tests d'intégration "accidentels".

Donc, dans votre code live, vous transmettez un objet REAL IBusinessDataEtc. Mais dans vos tests unitaires, vous transmettez un objet MOCK IBusinessDataEtc. Dans cette maquette, vous pouvez inclure des propriétés non liées à l'interface telles que int XMethodWasCalledCount ou quelque chose dont le ou les états sont mis à jour lors de l'appel des méthodes d'interface.

Ainsi, votre test unitaire examinera votre (vos) méthode (s) en question, exécutera sa logique et appellera une ou deux, ou un ensemble sélectionné de méthodes dans votre objet IBusinessDataEtc. Lorsque vous faites vos assertions à la fin de votre test unitaire, vous avez plusieurs choses à tester maintenant.

  1. Etat du "sous-programme" qui est maintenant une méthode Try-Paradigm.
  2. L'état de votre objet Mock IBusinessDataEtc.

Pour plus d'informations sur les idées d'injection de dépendance au niveau de la construction ... en ce qui concerne les tests unitaires ... examinez les modèles de conception de Builder. Il ajoute une interface et une classe de plus pour chaque interface/classe actuelle, mais elles sont très petites et fournissent d'énormes fonctionnalités pour un meilleur test unitaire.

10
Suamere

cela aura un effet sur un objet .... demande le résultat de l'effet. S'il n'a pas d'effet visible, cela ne vaut pas la peine de faire des tests unitaires!

5
Keith Nicholas

Vraisemblablement, la méthode fait quelque chose et ne retourne pas simplement?

En supposant que ce soit le cas, alors:

  1. S'il modifie l'état de son objet propriétaire, vous devez alors vérifier que l'état a été modifié correctement.
  2. S'il accepte un objet en tant que paramètre et le modifie, vous devez alors vérifier que l'objet est correctement modifié.
  3. S'il lève des exceptions dans certains cas, vérifiez que ces exceptions sont correctement levées.
  4. Si son comportement varie en fonction de l'état de son propre objet, ou de tout autre objet, prédéfinissez l'état et testez que la méthode a la valeur correcte pour l'une des trois méthodes de test ci-dessus).

Si vous nous faites savoir ce que fait la méthode, je pourrais être plus précis.

4
David Arno

Essaye ça:

[TestMethod]
public void TestSomething()
{
    try
    {
        YourMethodCall();
        Assert.IsTrue(true);
    }
    catch {
        Assert.IsTrue(false);
    }
}
4
Nathan Alard

Utilisez Rhino Mocks pour définir quels appels, actions et exceptions peuvent être attendus. En supposant que vous puissiez vous moquer ou tronquer des parties de votre méthode. Difficile de savoir sans connaître certains détails sur la méthode, ni même sur le contexte.

3
dove

Cela dépend de ce que ça fait. S'il y a des paramètres, transmettez des répliques que vous pourrez demander plus tard si elles ont été appelées avec le bon jeu de paramètres.

2
André

Vous pouvez même l'essayer de cette façon:

[TestMethod]
public void ReadFiles()
{
    try
    {
        Read();
        return; // indicates success
    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}
2
Reyan Chougle

Quelle que soit l’instance que vous utilisez pour appeler la méthode void, vous pouvez simplement utiliser, Verfiy

Par exemple:

Dans mon cas, c'est _Log est l'instance et LogMessage est la méthode à tester:

try
{
    this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure");
}
Catch 
{
    Assert.IsFalse(ex is Moq.MockException);
}

Est-ce que Verify lève une exception en raison de l'échec de la méthode dont le test aurait échoué?

0
Shreya Kesharkar