web-dev-qa-db-de.com

So verspotten Sie ConfigurationManager.AppSettings mit moq

Ich stecke an diesem Punkt des Codes fest, den ich nicht verspotten kann:

ConfigurationManager.AppSettings["User"];

Ich muss den ConfigurationManager verspotten, habe aber keine Ahnung, ich verwende Moq .

Kann mir jemand einen Tipp geben? Vielen Dank!

111
Otuyh

Ich glaube, ein Standardansatz hierfür ist die Verwendung eines Fassaden- Musters, um den Konfigurationsmanager einzuschließen, und dann haben Sie etwas lose Gekoppeltes, über das Sie die Kontrolle haben.

Sie würden also den ConfigurationManager umschließen. So etwas wie:

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

(Sie können einfach eine Schnittstelle aus Ihrer Konfigurationsklasse extrahieren und diese Schnittstelle dann überall in Ihrem Code verwenden.) Dann verspotten Sie einfach die IConfiguration. Möglicherweise können Sie die Fassade selbst auf verschiedene Arten implementieren. Oben habe ich nur die einzelnen Eigenschaften eingewickelt. Sie erhalten auch den Nebeneffekt, stark typisierte Informationen zu haben, mit denen Sie arbeiten können, anstatt schwach typisierte Hash-Arrays.

100
Joshua Enfield

Ich benutze AspnetMvc4. Vor einem Moment habe ich geschrieben

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

in meiner Testmethode und es hat einwandfrei funktioniert.

Erläuterung: Die Testmethode wird in einem Kontext mit App-Einstellungen ausgeführt, die normalerweise aus web.config Oder myapp.config Stammen. ConfigurationsManager kann dieses globale Anwendungsobjekt erreichen und bearbeiten.

Allerdings: Wenn Sie einen Testläufer haben, der Tests parallel durchführt, ist dies keine gute Idee.

142
LosManos

Vielleicht ist es nicht das, was Sie tun müssen, aber haben Sie darüber nachgedacht, eine app.config in Ihrem Testprojekt zu verwenden? Der ConfigurationManager erhält also die Werte, die Sie in die app.config eingegeben haben, und Sie müssen nichts verspotten. Diese Lösung funktioniert gut für meine Bedürfnisse, da ich nie eine "variable" Konfigurationsdatei testen muss.

21
Iridio

Sie können Shims verwenden, um AppSettings in ein benutzerdefiniertes NameValueCollection Objekt zu ändern. Hier ist ein Beispiel, wie Sie dies erreichen können:

[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.        
    }
}

Weitere Informationen zu Shims und Fakes finden Sie unter Isolieren des getesteten Codes mit Microsoft Fakes . Hoffe das hilft.

14
Zorayr

Haben Sie darüber nachgedacht, nicht zu spotten, sondern zu stottern? Die Eigenschaft AppSettings ist eine 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...
    }
}

Die Vorteile sind eine einfachere Implementierung und keine Abhängigkeit von System.Configuration, bis Sie es wirklich brauchen.

8
DanielLarsenNZ

Dies ist eine statische Eigenschaft, und Moq wurde für Moq-Instanzmethoden oder -Klassen entwickelt, die über die Vererbung verspottet werden können. Mit anderen Worten, Moq wird Ihnen hier keine Hilfe sein.

Zum Verspotten der Statik benutze ich ein Tool namens Moles , das kostenlos ist. Es gibt andere Framework-Isolationstools, wie Typemock, die dies ebenfalls können, obwohl ich glaube, dass dies kostenpflichtige Tools sind.

Wenn es um Statik und Testen geht, besteht eine andere Möglichkeit darin, den statischen Zustand selbst zu erstellen, obwohl dies häufig problematisch sein kann (wie ich mir in Ihrem Fall vorstellen würde).

Und schließlich, wenn die Isolations-Frameworks keine Option sind und Sie diesem Ansatz verpflichtet sind, ist die von Joshua erwähnte Fassade ein guter Ansatz oder ein Ansatz im Allgemeinen, bei dem Sie den Client-Code davon weg von der Geschäftslogik, die Sie verwenden, berücksichtigen verwenden, um zu testen.

2
Erik Dietrich

Ich denke, das Schreiben eines eigenen app.config-Providers ist eine einfache Aufgabe und nützlicher als alles andere. Vor allem sollten Sie Fälschungen wie Unterlegscheiben etc. vermeiden, denn sobald Sie diese verwenden, funktioniert Edit & Continue nicht mehr.

Die Anbieter, die ich benutze, sehen folgendermaßen aus:

Standardmäßig erhalten sie die Werte aus dem App.config aber für Komponententests kann ich alle Werte überschreiben und sie in jedem Test unabhängig verwenden.

Es sind keine Schnittstellen erforderlich und es muss nicht jedes Mal neu implementiert werden. Ich habe eine Dienstprogramm-DLL und benutze diesen kleinen Helfer in vielen Projekten und Unit-Tests.

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