web-dev-qa-db-fra.com

ConfigurationManager.AppSettings renvoie Null dans le projet de test unitaire

J'ai un projet de test unitaire C # avec des paramètres d'application dans le fichier app.config. Je teste une classe qui existe dans un projet différent. Cette classe dépend à la fois de ConfigurationManager.AppSettings et de ConfigurationManager.ConnectionStrings

Le projet dans lequel réside la classe testée ne possède pas de fichier app.config. J'aurais pensé que parce que la classe est instanciée dans le contexte du projet de test unitaire, elle utiliserait le fichier app.config du projet de test unitaire. En effet, cela semble être le cas pour la chaîne de connexion. 

La classe récupère la chaîne de connexion sans aucun problème. Toutefois, lorsque la classe tente de récupérer des paramètres d'application, le gestionnaire de configuration renvoie toujours null. Qu'est-ce qui se passe ici?

Modifier 1

J'ai pensé que ce serait peut-être une bonne idée d'essayer de charger certains paramètres dans le projet de test pour voir ce qui se passe. J'ai essayé de charger le paramètre dans le test unitaire immédiatement avant d'appeler le code qui instancie la classe dans le projet externe. Même résultat, rien. Je suppose que je peux exclure l’autre projet de l’équation pour le moment.

Voici un extrait de mon fichier de configuration:

<configSections>
  <sectionGroup name="applicationSettings"
                type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
    <section name="MyNamespace.Properties.Settings"
             type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
             requirePermission="false" />
  </sectionGroup>
</configSections>

...

<applicationSettings>
  <MyNamespace.Properties.Settings>
    <setting name="Bing_Key"
             serializeAs="String">
      <value>...</value>
    </setting>
  </MyNamespace.Properties.Settings>
</applicationSettings>

et voici comment je tente de charger le paramètre:

string test = System.Configuration.ConfigurationManager.AppSettings["Bing_Key"];
18
Jason Boyd

Vous avez mentionné des paramètres dans les propriétés du projet. Voyez si vous pouvez accéder au paramètre de cette façon:

string test = Properties.Settings.Default.Bing_Key;

Vous devrez peut-être obtenir l'assembly d'exécution du fichier de paramètres du projet, mais essayez d'abord.

MODIFIER

Lors de l'utilisation du fichier de paramètres de projet de Visual Studio, il ajoute des éléments à votre app.config et crée le fichier app.config s'il n'est pas présent. ConfigurationManager NE PEUT PAS toucher ces paramètres! Vous pouvez uniquement accéder à ce fichier project.settings généré spécifique en utilisant la méthode statique ci-dessus. Si vous souhaitez utiliser ConfigurationManager, vous devez écrire votre app.config à la main. Ajoutez-y vos paramètres comme ceci:

<appSettings>
  <add key="bing_api" value="whatever"/>
</appSettings>
6
Bill Sambrone

Pensez à refactoriser votre code qui accède à la configuration pour utiliser un wrapper. Ensuite, vous pouvez écrire des simulations pour la classe wrapper sans avoir à gérer l'importation du fichier de configuration pour le test.

Dans une bibliothèque commune aux deux, créez quelque chose comme ceci:

public interface IConfigurationWrapper {

    string GetValue(string key);
    bool HasKey(string key);
}

Ensuite, dans vos bibliothèques devant accéder à config, insérez une instance de ce type d'interface dans la classe devant lire config.

public class MyClassOne {

    private IConfigurationWrapper _configWrapper;

    public MyClassOne(IConfigurationWrapper wrapper) {
        _configWrapper = wrapper;
    } // end constructor

    public void MethodThatDependsOnConfiguration() {
        string configValue = "";
        if(_configWrapper.HasKey("MySetting")) {
            configValue = _configWrapper.GetValue("MySetting");
        }
    } // end method

} // end class MyClassOne

Ensuite, dans l’une de vos bibliothèques, créez une implémentation qui dépend du fichier de configuration.

public class AppConfigWrapper : IConfigurationWrapper {

    public string GetValue(string key) {
        return ConfigurationManager.AppSettings(key);
    }

    public bool HasKey(string key) {
       return ConfigurationManager.AppSettings.AllKeys.Select((string x) => x.ToUpperInvariant()).Contains(key.ToUpperInvariant());
    }
}

Ensuite, dans le code qui appelle votre classe.

//Some method container
MyClassOne dataClass = new MyClassOne(new AppConfigWrapper());

dataClass.MethodThatDependsOnConfiguration();

Ensuite, dans votre test, vous êtes libre de la servitude de dépendance. :) Vous pouvez soit créer une fausse version qui implémente IConfigurationWrapper et la transmettre pour votre test, en codant en dur les valeurs de retour des fonctions GetValue et HasKey, ou si vous utilisez une bibliothèque moqueuse comme Moq:

Mock<IConfigurationWrapper> fakeWrapper = new Mock<IConfigurationWrapper>();

fakeWrapper.Setup((x) => x.GetValue(It.IsAny<string>)).Returns("We just bypassed config.");

MyClassOne testObject = new MyClassOne(fakeWrapper.Object);
testObject.MethodThatDependsOnConfiguration();

Voici un article qui couvre le concept (bien que, pour les formulaires Web, mais les concepts sont les mêmes): http://www.schwammysays.net/how-to-unit-test-code-that-uses-appsettings -from-web-config/

10
xDaevax

Et puis il a crié "NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO".

Cite: J'ai un projet de test unitaire C # avec des paramètres d'application dans le fichier app.config. Je teste une classe qui existe dans un projet différent. Cette classe dépend à la fois de ConfigurationManager.AppSettings et de ConfigurationManager.ConnectionStrings. 

Tu ne fais pas ça. DÉJÀ!!!! Pourquoi? parce que vous avez maintenant créé une dépendance. Utilisez plutôt l'injection de dépendance afin que la classe puisse faire son travail sans avoir à passer par le fichier de configuration appartenant à l'application.

0
Gregory A Beamer