So testen Sie statische Methoden in C #

Beim Erstellen oder Arbeiten in .NET-Anwendungen verwenden Sie möglicherweise häufig statische Methoden. Methoden in C # können entweder statisch oder nicht statisch sein. Eine nicht statische Methode (auch als Instanzmethode bezeichnet) kann für eine Instanz der Klasse aufgerufen werden, zu der sie gehört. Für statische Methoden muss keine Instanz der Klasse aufgerufen werden. Sie können für die Klasse selbst aufgerufen werden.

Obwohl das Testen einer nicht statischen Methode (mindestens eine, die keine statische Methode aufruft oder mit externen Abhängigkeiten interagiert) unkompliziert ist, ist das Testen einer statischen Methode überhaupt keine leichte Aufgabe. In diesem Artikel wird erläutert, wie Sie diese Herausforderung bewältigen und statische Methoden in C # testen können. 

[Ebenfalls zu: Wie man Gottobjekte in C # umgestaltet]

Um mit den in diesem Artikel bereitgestellten Codebeispielen arbeiten zu können, muss Visual Studio 2019 auf Ihrem System installiert sein. Wenn Sie noch keine Kopie haben, können Sie Visual Studio 2019 hier herunterladen.  

Erstellen Sie ein .NET Core-Konsolenanwendungsprojekt in Visual Studio

Zunächst erstellen wir ein .NET Core Console-Anwendungsprojekt in Visual Studio. Angenommen, Visual Studio 2019 ist auf Ihrem System installiert, führen Sie die folgenden Schritte aus, um ein neues .NET Core-Konsolenanwendungsprojekt in Visual Studio zu erstellen.

  1. Starten Sie die Visual Studio-IDE.
  2. Klicken Sie auf "Neues Projekt erstellen".
  3. Wählen Sie im Fenster "Neues Projekt erstellen" aus der Liste der angezeigten Vorlagen "Konsolen-App (.NET Core)" aus.
  4. Weiter klicken.
  5. Geben Sie im nächsten Fenster "Konfigurieren Sie Ihr neues Projekt" den Namen und den Speicherort für das neue Projekt an.
  6. Klicken Sie auf Erstellen. 

Dadurch wird ein neues .NET Core-Konsolenanwendungsprojekt in Visual Studio 2019 erstellt. Erstellen Sie auf ähnliche Weise zwei weitere Projekte - eine Klassenbibliothek und ein Unit-Test-Projekt (xUnit-Test). Wir werden diese drei Projekte verwenden, um das Testen von statischen Methoden in den folgenden Abschnitten dieses Artikels zu veranschaulichen.

Wenn eine statische Methode Unit-getestet werden kann und nicht

Das Testen einer statischen Methode durch Einheiten unterscheidet sich nicht vom Testen einer nicht statischen Methode mit Einheiten. Statische Methoden sind an sich nicht unprüfbar. Eine statische Methode, die keinen Status enthält oder den Status nicht ändert, kann Unit-getestet werden. Solange die Methode und ihre Abhängigkeiten idempotent sind, kann die Methode einem Unit-Test unterzogen werden. Die Probleme treten auf, wenn die statische Methode andere Methoden aufruft oder wenn das zu testende Objekt die statische Methode aufruft. Wenn das getestete Objekt hingegen eine Instanzmethode aufruft, können Sie es problemlos einem Komponententest unterziehen.

Eine statische Methode kann nicht einheitlich getestet werden, wenn eine der folgenden Bedingungen erfüllt ist: 

  • Die statische Methode interagiert mit externen Abhängigkeiten wie einer Datenbank, einem Dateisystem, einem Netzwerk oder einer externen API.
  • Die statische Methode enthält Statusinformationen, dh wenn sie Daten in einem statischen Objekt der Klasse zwischenspeichert.

Betrachten Sie das folgende Codefragment, das zwei Klassen anzeigt, nämlich ProductBL und Logger. Während ProductBL eine nicht statische Klasse ist, ist Logger eine statische Klasse. Beachten Sie, dass die Write-Methode der Logger-Klasse von der LogMessage-Methode der ProductBL-Klasse aufgerufen wurde.

öffentliche Klasse ProductBL

    {

        public void LogMessage (Zeichenfolgenachricht)

        {

            Logger.Write (Nachricht);

        }}

    }}

    Logger der öffentlichen Klasse

    {

        public static void Write (Zeichenfolgenachricht)

        {

           // Schreiben Sie Ihren Code hier, um Daten zu protokollieren

        }}

    }}

Angenommen, die Write-Methode der Logger-Klasse stellt eine Verbindung zu einer Datenbank her und schreibt die Daten dann in eine Datenbanktabelle. Der Name der Datenbank und ihre Tabelle, in die die Daten geschrieben werden sollen, sind möglicherweise in der Datei appsettings.json vorkonfiguriert. Wie können Sie jetzt Unit-Tests für die ProductBL-Methode schreiben?

Beachten Sie, dass statische Methoden nicht einfach verspottet werden können. Wenn Sie beispielsweise zwei Klassen mit den Namen A und B haben und Klasse A ein statisches Mitglied der Klasse B verwendet, können Sie die Klasse A nicht isoliert testen.

Drei Möglichkeiten, statische Methoden zu testen

Sie können Moq verwenden, um nicht statische Methoden zu verspotten, aber es kann nicht verwendet werden, um statische Methoden zu verspotten. Obwohl statische Methoden nicht einfach verspottet werden können, gibt es einige Möglichkeiten, statische Methoden zu verspotten.

Sie können das Moles or Fakes-Framework von Microsoft nutzen, um statische Methodenaufrufe zu verspotten. (Das Fakes-Framework wurde in Visual Studio 2012 als Nachfolger von Moles aufgenommen - es ist die nächste Generation von Moles und Stubs.) Eine andere Möglichkeit, statische Methodenaufrufe zu verspotten, ist die Verwendung von Delegaten. Es gibt noch eine andere Möglichkeit, statische Methodenaufrufe in einer Anwendung zu verspotten - mithilfe von Wrapper-Klassen und Abhängigkeitsinjektion.

IMHO ist diese letzte Option die beste Lösung für das Problem. Sie müssen lediglich den statischen Methodenaufruf in eine Instanzmethode einbinden und dann mithilfe der Abhängigkeitsinjektion eine Instanz der Wrapper-Klasse in die zu testende Klasse einfügen.

Erstellen Sie eine Wrapper-Klasse in C #

Das folgende Codefragment veranschaulicht die LogWrapper-Klasse, die die IWrapper-Schnittstelle implementiert und einen Aufruf der Logger.Write () -Methode in eine Instanzmethode namens LogData einschließt.

öffentliche Klasse LogWrapper: IWrapper

    {

        Zeichenfolge _message = null;

        öffentlicher LogWrapper (String-Nachricht)

        {

            _message = message;

        }}

        public void LogData (Zeichenfolgenachricht)

        {

            _message = message;

            Logger.Write (_message);

        }}

    }}

Das folgende Codefragment zeigt die IWrapper-Schnittstelle. Es enthält die Deklaration der LogData-Methode.

öffentliche Schnittstelle IWrapper

    {

        void LogData (String-Nachricht);

    }}

Die ProductBL-Klasse verwendet die Abhängigkeitsinjektion (Konstruktorinjektion), um eine Instanz der LogWrapper-Klasse zu injizieren, wie in der unten angegebenen Codeliste gezeigt.

öffentliche Klasse ProductBL

    {

        schreibgeschützt IWrapper _wrapper;

        statische Zeichenfolge _message = null;

        public ProductBL (IWrapper-Wrapper)

        {

            _wrapper = wrapper;

        }}

        public void LogMessage (Zeichenfolgenachricht)

        {

            _message = message;

            _wrapper.LogData (_message);

        }}

    }}

Die LogMessage-Methode der ProductBL-Klasse ruft die LogData-Methode für die Instanz der LogWrapper-Klasse auf, die zuvor injiziert wurde.

Verwenden Sie xUnit und Moq, um eine Unit-Test-Methode in C # zu erstellen

Öffnen Sie die Datei UnitTest1.cs und benennen Sie die UnitTest1-Klasse in UnitTestForStaticMethodsDemo um. Die UnitTest1.cs-Dateien werden automatisch in UnitTestForStaticMethodsDemo.cs umbenannt. Wir werden jetzt das Moq-Framework nutzen, um Mocks einzurichten, zu testen und zu verifizieren.

Das folgende Codefragment zeigt, wie Sie das Moq-Framework verwenden können, um Testmethoden in C # zu vereinheitlichen.

var mock = new Mock ();

mock.Setup (x => x.LogData (It.IsAny ()));

neues ProductBL (mock.Object) .LogMessage ("Hallo Welt!");

mock.VerifyAll ();

Wenn Sie den Test ausführen, sollte die Ausgabe im Test Explorer-Fenster folgendermaßen aussehen.

Die vollständige Codeliste der Testklasse finden Sie unten als Referenz.

öffentliche Klasse UnitTestForStaticMethodsDemo

    {

        [Tatsache]

        public void StaticMethodTest ()

        {

            var mock = new Mock ();

            mock.Setup (x => x.LogData (It.IsAny ()));

            neues ProductBL (mock.Object) .LogMessage ("Hallo Welt!");

            mock.VerifyAll ();

        }}

    }}

Unit-Tests sind ein Prozess, bei dem Codeeinheiten in einer Anwendung getestet werden, um zu überprüfen, ob die tatsächlichen Ergebnisse Ihres Unit-Tests mit den gewünschten Ergebnissen übereinstimmen. Bei vernünftiger Anwendung können Unit-Tests dazu beitragen, Fehler in der Entwicklungsphase eines Projekts zu vermeiden.

Statische Methoden können eine Reihe von Problemen aufwerfen, wenn Sie versuchen, sie mithilfe von Mocks zu testen. Wenn Sie in Ihrer Anwendung eine statische Methode verspotten müssen, sollten Sie berücksichtigen, dass ein Design riecht - dh ein Indikator für ein schlechtes Design. Ich werde Mocks, Fakes und Stubs in einem zukünftigen Artikel hier ausführlicher besprechen.

So machen Sie mehr in C #:

  • Wie man Gottobjekte in C # umgestaltet
  • Verwendung von ValueTask in C #
  • Verwendung der Unveränderlichkeit in C.
  • Verwendung von const, readonly und static in C #
  • Verwendung von Datenanmerkungen in C #
  • So arbeiten Sie mit GUIDs in C # 8
  • Wann wird eine abstrakte Klasse im Vergleich zur Schnittstelle in C # verwendet?
  • So arbeiten Sie mit AutoMapper in C #
  • Verwendung von Lambda-Ausdrücken in C #
  • So arbeiten Sie mit Action-, Func- und Predicate-Delegaten in C #
  • So arbeiten Sie mit Delegierten in C #
  • So implementieren Sie einen einfachen Logger in C #
  • So arbeiten Sie mit Attributen in C #
  • So arbeiten Sie mit log4net in C #
  • So implementieren Sie das Repository-Entwurfsmuster in C #
  • Wie man mit Reflexion in C # arbeitet
  • So arbeiten Sie mit dem Dateisystemwatcher in C #
  • So führen Sie eine verzögerte Initialisierung in C # durch
  • So arbeiten Sie mit MSMQ in C #
  • So arbeiten Sie mit Erweiterungsmethoden in C #
  • Wie wir Lambda-Ausdrücke in C #
  • Wann wird das flüchtige Schlüsselwort in C # verwendet?
  • Verwendung des Schlüsselwortsield in C #
  • So implementieren Sie Polymorphismus in C #
  • So erstellen Sie Ihren eigenen Taskplaner in C #
  • So arbeiten Sie mit RabbitMQ in C #
  • So arbeiten Sie mit einem Tupel in C #
  • Erkundung virtueller und abstrakter Methoden in C #
  • Verwendung des Dapper ORM in C #
  • Verwendung des Entwurfsmusters im Fliegengewicht in C #