2008-10-03 6 views
57

Lorsque vous testez une unité, une application qui repose sur les valeurs d'un fichier app.config? Comment testez-vous que ces valeurs sont lues correctement et comment votre programme réagit aux valeurs incorrectes entrées dans un fichier de configuration?Unité testant le fichier app.config avec NUnit

Il serait ridicule d'avoir à modifier le fichier de configuration pour l'application NUnit, mais je ne peux pas lire les valeurs de l'app.config que je veux tester.

Edit: Je pense que je devrais peut-être clarifier. Je ne m'inquiète pas du fait que ConfigurationManager n'a pas lu les valeurs, mais je suis préoccupé par la façon dont mon programme réagit aux valeurs lues.

Répondre

41

J'ai l'habitude d'isoler les dépendances externes comme lire un fichier de configuration dans leur propre classe de façade avec très peu de fonctionnalités. Dans les tests, je peux créer une version fictive de cette classe qui implémente et utilise celle-ci à la place du vrai fichier de configuration. Vous pouvez créer votre propre maquette ou utiliser un framework comme moq ou rhinocéros pour cela. De cette façon, vous pouvez facilement tester votre code avec différentes valeurs de configuration sans écrire de tests complexes qui écrivent d'abord des fichiers de configuration xml. Le code qui lit la configuration est généralement si simple qu'il nécessite très peu de tests.

+3

C'est effrayant de voir que cette réponse n'a pas eu plus de votes upvotes et que d'autres réponses parlant d'ajouter/lire/éditer des fichiers de configuration ont autant de points. Pour les lecteurs, cette réponse est la voie à suivre pour que vos tests unitaires restent simples et SOLIDES. –

+0

"Il n'y a aucun problème qui ne peut être résolu en ajoutant une autre couche d'abstraction." :-) – Iain

0

En fait, en y réfléchissant plus, je suppose que je dois créer un Classe ConfigFileReader à utiliser dans mon projet, puis fake-le dans le harnais de test unitaire?

Est-ce la chose habituelle à faire?

16

Vous pouvez lire et écrire dans le fichier app.config avec la ConfigurationManager classe

+2

Ahhh, donc je peux définir des valeurs dans la collection ConfigurationManager? J'ai toujours supposé que c'était en lecture seule. Je suppose que c'est ce que j'ai pour faire des suppositions: P – Dana

+3

J'ai juste essayé ça, et ça marche super! Par exemple, 'ConfigurationManager.AppSettings [" SomeKey "] =" MockValue ";'. Bonne réponse! –

+0

Quand je l'ai essayé change la valeur de la clé que vous spécifiez mais supprime également les valeurs et toutes les autres touches :( – Yasser

1

Vous pouvez toujours envelopper le bit de lecture dans dans une interface et une implémentation spécifique lue à partir du fichier de configuration. Vous écrivez ensuite des tests en utilisant des objets Mock pour voir comment le programme a géré les mauvaises valeurs. Personnellement, je ne testerais pas cette implémentation spécifique, car il s'agit du code .NET Framework (et je suppose - espérons-le - que la MS l'a déjà testé).

0

L'option la plus simple consiste à recouvrir les méthodes qui lisent la configuration de sorte que vous puissiez les remplacer par des valeurs pendant le test. Créer une interface que vous utilisez pour lire config et avoir une implémentation de cette interface est passée en tant que paramètre constructeur ou définie sur l'objet en tant que propriété (comme vous le feriez en utilisant l'injection de dépendance/inversion de contrôle). Dans l'environnement de production, transmettez une implémentation qui lit réellement à partir de la configuration; dans l'environnement de test, transmettez une implémentation de test qui renvoie une valeur connue. Si vous n'avez pas la possibilité de refactoriser le code pour la testabilité mais que vous devez encore le tester, Typemock Isolator vous permet de simuler les classes de configuration de l'infrastructure .NET pour que vous puissiez simplement dire "la prochaine fois que je demande telle et telle appSettings value, renvoie cette valeur connue. "

0

J'ai eu le même problème,

vous pouvez utiliser Nunit-console.exe c: \ chemin1 \ testdll1.dll c: \ chemin2 \ testdll2.dll

cela fonctionne bien, même si, si les deux dll à des priorités différentes app.configs ex testdll1.dll.config et testdll2.dll.config

si vous voulez utiliser config de projet Nunit et envelopper ces deux dll alors il n'y a aucun moyen que vous pouvez avoir deux configs

vous devez avoir project1.config si votre projet Nunit est project1.nunit au même endroit que Project1.nunit.

Espérons que cela aide

29

Vous pouvez modifier votre section de configuration lors de l'exécution dans la configuration de votre test. E.g:

// setup 
System.Configuration.Configuration config = 
    ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 
config.Sections.Add("sectionname", new ConfigSectionType()); 
ConfigSectionType section = (ConfigSectionType)config.GetSection("sectionname"); 
section.SomeProperty = "value_you_want_to_test_with"; 
config.Save(ConfigurationSaveMode.Modified); 
ConfigurationManager.RefreshSection("sectionname"); 

// carry out test ... 

Vous pouvez bien sûr configurer vos propres méthodes d'assistance pour le faire plus élégamment.

+0

La lecture d'un fichier à partir d'un disque fait que toute la suite de tests se transforme en tests d'intégration. Vous n'êtes plus un test unitaire car il existe des dépendances d'état globales et externes. – kai

11

Je faisais face à des problèmes similaires avec web.config .... Je trouve une solution intéressante. Vous pouvez encapsuler la fonction de lecture de configuration, par ex. quelque chose comme ceci:

public class MyClass { 

public static Func<string, string> 
    GetConfigValue = s => ConfigurationManager.AppSettings[s]; 

//... 

} 

Et puis utilisez normalement

string connectionString = MyClass.GetConfigValue("myConfigValue"); 

mais test unitaire initaliser "override" la fonction comme ceci:

MyClass.GetConfigValue = s => s == "myConfigValue" ? "Hi", "string.Empty"; 

Pour en savoir plus:

http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/

3

Une solution plus élégante consiste à utiliser l'ancienne injection de dépendance simple sur les paramètres de configuration eux-mêmes. À mon humble avis cela est plus propre que d'avoir à se moquer d'une classe de lecture de configuration/wrapper etc.

Par exemple, disons une classe "Météo" nécessite un "ServiceUrl" pour fonctionner (par exemple dire qu'il appelle un service Web pour obtenir la météo). Plutôt que d'avoir une ligne de code qui va activement à un fichier de configuration pour obtenir ce paramètre (que ce code soit dans la classe Weather ou un lecteur de configuration séparé qui pourrait être raillé selon certaines des autres réponses), la classe Weather peut autoriser le paramètre à injecter, soit via un paramètre au constructeur, soit éventuellement via un setter de propriétés. De cette façon, les tests unitaires sont extrêmement simples et directs, et ne nécessitent même pas de se moquer. La valeur du paramètre peut ensuite être injectée à l'aide d'un conteneur Inversion of Control (ou Dependency Injection), de sorte que les utilisateurs de la classe Weather n'ont pas besoin de fournir explicitement la valeur de quelque part, car elle est gérée par le conteneur .

2

Cela a fonctionné pour moi:

public static void BasicSetup() 
    { 
    ConnectionStringSettings connectionStringSettings = 
      new ConnectionStringSettings(); 
    connectionStringSettings.Name = "testmasterconnection"; 
    connectionStringSettings.ConnectionString = 
      "server=localhost;user=some;database=some;port=3306;"; 
    ConfigurationManager.ConnectionStrings.Clear(); 
    ConfigurationManager.ConnectionStrings.Add(connectionStringSettings); 
    } 
20

Vous pouvez appeler la méthode ensemble de ConfigurationManager.AppSettings pour définir les valeurs requises pour ce test d'unité.

[SetUp] 
public void SetUp() 
{ 
    ConfigurationManager.AppSettings.Set("SettingKey" , "SettingValue"); 
    // rest of unit test code follows 
} 

Lorsque le test de l'unité exécute ensuite utiliser ces valeurs pour exécuter le code

+2

C'était de loin le moyen le plus facile de le résoudre pour mes fins. Mon code vient de vérifier si la clé nommée Environnement était TEST ou LIVE. Donc, je viens de mettre la clé à TEST au début de la méthode de test unitaire. –

0

Eh bien, je viens d'avoir le même problème ... je voulais tester un projet BL qui est référencé à partir d'un site Internet . mais je voulais tester le BL seulement. Donc, dans l'événement de pré-construction du projet de test, je copie les fichiers app.Config dans le dossier bin \ debug et les référence à partir de l'app.config ...

Questions connexes