Verwendung von Moq zur Vereinfachung von Unit-Tests in C #

Wir müssen häufig Komponententests für Code schreiben, der auf eine externe Ressource wie eine Datenbank oder ein Dateidateisystem zugreift. Wenn solche Ressourcen nicht verfügbar sind, können Sie nur sicherstellen, dass die Tests ausgeführt werden können, indem Sie Scheinobjekte erstellen. Im Wesentlichen können Sie die Interaktion zwischen der zu testenden Methode und ihren Abhängigkeiten testen, indem Sie auf gefälschte Implementierungen dieser zugrunde liegenden Abhängigkeiten zurückgreifen. Drei der beliebtesten Mocking-Frameworks für .NET-Entwickler sind Rhino Mocks, Moq und NMock.

Unter diesen ist Moq möglicherweise das flexibelste und am einfachsten zu verwendende. Das Moq-Framework bietet eine elegante Möglichkeit zum Einrichten, Testen und Überprüfen von Mocks. Dieser Artikel enthält eine Diskussion über Moq und wie es verwendet werden kann, um Codeeinheiten von ihren Abhängigkeiten zu isolieren.

Erste Schritte mit Moq

Mit Moq können Sie Scheinobjekte erstellen, die ein reales Objekt simulieren oder nachahmen. Moq kann verwendet werden, um sowohl Klassen als auch Schnittstellen zu verspotten. Es gibt jedoch einige Einschränkungen, die Sie beachten sollten. Die zu verspottenden Klassen können nicht statisch oder versiegelt sein, und die zu verspottende Methode sollte als virtuell markiert werden. (Beachten Sie, dass diese Einschränkungen umgangen werden können. Sie können eine statische Methode verspotten, indem Sie beispielsweise das Adapter-Entwurfsmuster nutzen.)

Der erste Schritt bei der Verwendung von Moq besteht darin, es zu installieren, damit Sie es in Ihrem Unit-Test-Projekt verwenden können. Sie können Moq von GitHub herunterladen und gegebenenfalls Referenzen hinzufügen. Ich bevorzuge jedoch die Installation von Moq über NuGet, da es sowohl einfacher als auch weniger wahrscheinlich ist, Referenzen zu verpassen. Sie können Moq mit dem folgenden Befehl in der NuGet-Befehlszeile installieren.

Install-Package Moq

Wie man Schnittstellen mit Moq verspottet

Beginnen wir damit, eine Schnittstelle zu verspotten. Die Syntax zum Erstellen eines Scheinobjekts mit der Mock-Klasse ist unten angegeben.

Mock mockObjectType = new Mock ();

Betrachten Sie nun die folgende Schnittstelle mit dem Namen IAuthor.

öffentliche Schnittstelle IAuthor

    {

        int Id {get; einstellen; }}

        Zeichenfolge Vorname {get; einstellen; }}

        Zeichenfolge Nachname {get; einstellen; }}

    }}

Mit dem Moq-Framework können Sie ein Scheinobjekt erstellen, Eigenschaftswerte festlegen, Parameter angeben und Werte für die Methodenaufrufe zurückgeben. Das folgende Codeausschnitt zeigt, wie Sie mit Moq eine Instanz über die IAuthor-Schnittstelle erstellen können.

var mock = new Mock ();

Beachten Sie, dass die Mock-Klasse zum Moq-Framework gehört und einen generischen Konstruktor enthält, der den Typ der Schnittstelle akzeptiert, die Sie erstellen möchten. Moq nutzt Lambda-Ausdrücke, Delegaten und Generika. All dies macht die Verwendung des Frameworks sehr intuitiv.

Das folgende Codefragment zeigt, wie Sie die IAuthor-Schnittstelle verspotten und die Eigenschaften der verspotteten Instanz mit den entsprechenden Werten versehen können. Beachten Sie, wie wir Assert verwenden, um die Werte der Eigenschaften der verspotteten Instanz zu überprüfen.

var author = new Mock ();

author.SetupGet (p => p.Id) .Returns (1);

author.SetupGet (p => p.FirstName) .Returns ("Joydip");

author.SetupGet (p => p.LastName) .Returns ("Kanjilal");

Assert.AreEqual ("Joydip", author.Object.FirstName);

Assert.AreEqual ("Kanjilal", author.Object.LastName);

Wie man Methoden mit Moq verspottet

Betrachten wir nun die folgende Klasse mit dem Namen Article. Die Article-Klasse enthält nur eine Methode namens GetPublicationDate, die eine Artikel-ID als Parameter akzeptiert und das Veröffentlichungsdatum des Artikels zurückgibt.

Artikel der öffentlichen Klasse

    {

        public virtual DateTime GetPublicationDate (int articleId)

        {

            neue NotImplementedException () auslösen;

        }}

    }}

Da die GetPublicationDate-Methode noch nicht in der Article-Klasse implementiert ist, wurde die Methode verspottet, um das aktuelle Datum als Veröffentlichungsdatum zurückzugeben, wie im unten angegebenen Code-Snippet gezeigt.

var mockObj = new Mock ();
mockObj.Setup (x => x.GetPublicationDate (It.IsAny ())). Returns ((int x) => DateTime.Now);

Die Setup-Methode wird verwendet, um das Verhalten einer Methode zu definieren, die als Parameter an sie übergeben wird. In diesem Beispiel wird das Verhalten der GetPublicationDate-Methode definiert. Der Aufruf von It.IsAny()impliziert, dass die GetPublicationDate-Methode einen Parameter vom Typ Integer akzeptiert. Itbezieht sich auf eine statische Klasse. Die Returns-Methode wird verwendet, um den Rückgabewert der im Setup-Methodenaufruf angegebenen Methode anzugeben. In diesem Beispiel wird mit der Returns-Methode der Rückgabewert der Methode als aktuelles Systemdatum angegeben.

Mit Moq können Sie überprüfen, ob eine bestimmte Methode oder eine Eigenschaft aufgerufen wurde. Das folgende Codefragment veranschaulicht dies.

mockObj.Verify (t => t.GetPublicationDate (It.IsAny ()));

Hier verwenden wir die Verify-Methode, um festzustellen, ob GetPublicationDate für das Mock-Objekt aufgerufen wurde.

Wie man Basisklassenmethoden mit Moq verspottet

Betrachten Sie den folgenden Code. Wir haben hier zwei Klassen - die RepositoryBase-Klasse und die AuthorRepository-Klasse, die sie erweitert.

öffentliche abstrakte Klasse RepositoryBase

{

    öffentlicher virtueller Bool IsServiceConnectionValid ()

    {

        // Code

    }}

}}

öffentliche Klasse AuthorRepository: RepositoryBase

{

    public void Save ()

    {

        if (IsServiceConnectionValid ())

        {

            // Code

        }}

    }}

}}

Angenommen, wir möchten überprüfen, ob die Datenbankverbindung gültig ist. Möglicherweise möchten wir jedoch nicht den gesamten Code in der IsServiceConnectionValid-Methode testen. Beispielsweise kann die IsServiceConnectionValid-Methode Code enthalten, der sich auf eine Bibliothek eines Drittanbieters bezieht. Das wollen wir doch nicht testen, oder? Hier hilft die CallBase-Methode in Moq. 

In solchen Situationen, in denen Sie eine Methode in der Basisklasse haben, die im verspotteten Typ überschrieben wurde, und Sie nur die Basisversion der überschriebenen Methode verspotten müssen, können Sie auf CallBase zurückgreifen. Das folgende Codeausschnitt zeigt, wie Sie ein Teil-Mock-Objekt der AuthorRepository-Klasse erstellen können, indem Sie die CallBase-Eigenschaft auf true setzen.

var mockObj = new Mock () {CallBase = true};

mockObj.Setup (x => x.IsServiceConnectionValid ()). Returns (true);

Das Moq-Framework erleichtert das Erstellen von Scheinobjekten, die das Verhalten von Klassen und Schnittstellen zum Testen nachahmen, mit genau der Funktionalität, die Sie benötigen. Weitere Informationen zum Testen mit Mocks finden Sie in diesem großartigen Artikel von Martin Fowler.