web-dev-qa-db-fra.com

Comment se moquer de ConfigurationManager.AppSettings avec moq

Je suis bloqué à ce point de code que je ne sais pas comment se moquer:

ConfigurationManager.AppSettings["User"];

Je dois me moquer du ConfigurationManager, mais je n'ai pas la moindre idée, j'utilise Moq .

Quelqu'un peut me donner un pourboire? Merci!

111
Otuyh

Je crois qu’une approche standard consiste à utiliser un motif façade pour envelopper le gestionnaire de configuration, ce qui vous donne le contrôle sur quelque chose de mal couplé.

Vous allez donc envelopper le ConfigurationManager. Quelque chose comme:

public class Configuration: IConfiguration
{
    public User
    {
        get{ 
               return ConfigurationManager.AppSettings["User"];
       }
    }
}

(Vous pouvez simplement extraire une interface de votre classe de configuration, puis utiliser cette interface partout dans votre code). Ensuite, il vous suffit de vous moquer de IConfiguration. Vous pourrez peut-être mettre en œuvre la façade elle-même de différentes manières. Ci-dessus, j'ai juste choisi d'envelopper les propriétés individuelles. Vous bénéficiez également de l'avantage de disposer d'informations fortement typées, plutôt que de tableaux de hachage faiblement typés.

100
Joshua Enfield

J'utilise AspnetMvc4. Il y a un instant j'ai écrit

ConfigurationManager.AppSettings["mykey"] = "myvalue";

dans ma méthode de test et cela a fonctionné parfaitement.

Explanation: la méthode de test s'exécute dans un contexte avec les paramètres d'application pris, généralement un web.config ou myapp.config. ConfigurationsManager peut atteindre cet objet d'application global et le manipuler.

Bien que: si vous avez un coureur de test exécutant des tests en parallèle, ce n'est pas une bonne idée.

142
LosManos

Peut-être n’est-ce pas ce que vous devez accomplir, mais avez-vous envisagé d’utiliser un app.config dans votre projet de test? Ainsi, le ConfigurationManager obtiendra les valeurs que vous avez entrées dans le fichier app.config et vous n'avez pas besoin de vous moquer de rien. Cette solution fonctionne bien pour mes besoins, car je n'ai jamais besoin de tester un fichier de configuration "variable".

21
Iridio

Vous pouvez utiliser des cales pour modifier AppSettings en un objet personnalisé NameValueCollection. Voici un exemple de la façon dont vous pouvez y parvenir:

[TestMethod]
public void TestSomething()
{
    using(ShimsContext.Create()) {
        const string key = "key";
        const string value = "value";
        ShimConfigurationManager.AppSettingsGet = () =>
        {
            NameValueCollection nameValueCollection = new NameValueCollection();
            nameValueCollection.Add(key, value);
            return nameValueCollection;
        };

        ///
        // Test code here.
        ///

        // Validation code goes here.        
    }
}

Pour en savoir plus sur les cales et les contrefaçons, consultez Isolation du code sous test avec Microsoft Fakes . J'espère que cela t'aides.

14
Zorayr

Avez-vous envisagé d'abattre au lieu de vous moquer? La propriété AppSettings est un NameValueCollection:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        // Arrange
        var settings = new NameValueCollection {{"User", "Otuyh"}};
        var classUnderTest = new ClassUnderTest(settings);

        // Act
        classUnderTest.MethodUnderTest();

        // Assert something...
    }
}

public class ClassUnderTest
{
    private readonly NameValueCollection _settings;

    public ClassUnderTest(NameValueCollection settings)
    {
        _settings = settings;
    }

    public void MethodUnderTest()
    {
        // get the User from Settings
        string user = _settings["User"];

        // log
        Trace.TraceInformation("User = \"{0}\"", user);

        // do something else...
    }
}

Les avantages sont une implémentation plus simple et aucune dépendance de System.Configuration jusqu'à ce que vous en ayez vraiment besoin.

8
DanielLarsenNZ

C'est une propriété statique, et Moq est conçu pour les méthodes d'instance Moq ou les classes pouvant être simulées via l'héritage. En d'autres termes, Moq ne vous aidera pas ici.

Pour me moquer de la statique, j'utilise un outil appelé Moles , qui est gratuit. Il existe d'autres outils d'isolation de la structure, tels que Typemock, qui peuvent le faire également, bien que je pense que ce sont des outils payants.

Pour ce qui est de la statique et des tests, une autre option consiste à créer l’état statique vous-même, bien que cela puisse souvent être problématique (comme, j’imagine que ce serait le cas dans votre cas).

Et, enfin, si les cadres d'isolation ne sont pas une option et que vous vous engagez dans cette approche, la façade mentionnée par Joshua est une bonne approche, ou toute approche en général dans laquelle vous éliminez le code client de la logique métier. utilisez pour tester.

2
Erik Dietrich

Je pense que l’écriture de votre propre fournisseur app.config est une tâche simple et qu’elle est plus utile qu’autre chose. En particulier, vous devez éviter les faux, comme les cales, etc., car dès que vous les utilisez, les fonctions Modifier et continuer ne fonctionnent plus.

Les fournisseurs que j'utilise ressemblent à ceci:

Par défaut, ils obtiennent les valeurs du App.config mais pour les tests unitaires, je peux remplacer toutes les valeurs et les utiliser indépendamment pour chaque test.

Aucune interface ni implémentation ne sont nécessaires à chaque fois. J'ai un utilitaire dll et utilise ce petit assistant dans de nombreux projets et tests unitaires.

public class AppConfigProvider
{
    public AppConfigProvider()
    {
        ConnectionStrings = new ConnectionStringsProvider();
        AppSettings = new AppSettingsProvider();
    }

    public ConnectionStringsProvider ConnectionStrings { get; private set; }

    public AppSettingsProvider AppSettings { get; private set; }
}

public class ConnectionStringsProvider
{
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

    public string this[string key]
    {
        get
        {
            string customValue;
            if (_customValues.TryGetValue(key, out customValue))
            {
                return customValue;
            }

            var connectionStringSettings = ConfigurationManager.ConnectionStrings[key];
            return connectionStringSettings == null ? null : connectionStringSettings.ConnectionString;
        }
    }

    public Dictionary<string, string> CustomValues { get { return _customValues; } }
}

public class AppSettingsProvider
{
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

    public string this[string key]
    {
        get
        {
            string customValue;
            return _customValues.TryGetValue(key, out customValue) ? customValue : ConfigurationManager.AppSettings[key];
        }
    }

    public Dictionary<string, string> CustomValues { get { return _customValues; } }
}
1
t3chb0t