27. Januar 2014 · von Steffen Nörtershäuser

Erklärt: CRM 2013 Unit Test mit Webservice

Dieser Artikel ist eine Fortsetzung des Artikels CRM 2013 Unit Tests. Wie bereits zum Ende des vorherigen Artikels erwähnt, ist der Unit Test dort noch nicht vollständig isoliert, da er auf einen externen Webservice angewiesen ist. Dadurch könnte der Unit Test fehlschlagen, ohne dass der Fehler innerhalb des eigenen Programmcodes ist.

Wie dieses Problem mit Hilfe von Visual Studio gelöst werden kann, werde ich im Rahmen dieses Artikels aufzeigen.

Microsoft Fakes
Mithilfe von Visual Studio 2012 und Microsoft Fakes & Stubs können Methodenaufrufe umgebogen werden so das eine eigene Funktionalität aufgerufen wird. In unserem Beispiel heißt dies konkret das der Aufruf der getBank Webservice Methode durch eine eigene Funktion ersetzt wird welche nicht den Webservice anfragt, sondern die Daten unter Kontrolle des UnitTests zurückliefert. Dies kann über Shims erreicht werden welches ich im nächsten Schritt erklären werde. Dabei muss der PluginCode nicht verändert werden sondern alle Änderungen erfolgt innerhalb des Tests.

Erwähnenswert ist noch, dass hierzu Visual Studio 2012 Ultimate oder Visual Studio 2012 Premium mit Update 2 benötigt wird.

Hinzufügen von Fake Assemblies
Bevor man mit Microsoft Fakes & Stubs innerhalb des Unit Tests arbeiten kann, müssen sogenannte Fake Assemblies hinzugefügt werden. Dafür muss innerhalb des Test Projekts über einen Rechtsklick auf den Verweis zum Plugin Projekt eine Fakes Assembly generiert werden:
add_fake_assembly

Das generieren der Fakes Assembly kann mitunter eine gewisse Zeit in Anspruch nehmen.

Anpassen des Unit Test
Nun kann der Unit Test angepasst werden um die externe Abhängigkeit zum Bankleitzahl Webservice aufzulösen. Auch hier wieder zu erst der Programmcode und anschließend die Erklärung:

        /// <summary>
        /// Prüft ob der Bankname bei einer korrekten Bankleitzahl korrekt ermittelt wird
        /// </summary>
        [TestMethod]
        public void GetBankNameTest()
        {
            using (ShimsContext.Create())
            {
                // Arrange
                const string filename = "TestFiles/account-Create-001.xml";

                MyServiceProvider serviceProvider = new MyServiceProvider(filename);
                PreAccountCreateGetBankName plugin = new PreAccountCreateGetBankName();

                CrmUnitTest.Plugins.BLZService.Fakes.ShimBLZServicePortTypeClient.AllInstances.getBankString = (portTypeClient, bankCode) =>
                {
                    CrmUnitTest.Plugins.BLZService.detailsType result = new CrmUnitTest.Plugins.BLZService.detailsType();
                    result.bezeichnung = "Postbank (Giro)";

                    return result;
                };

                // Act
                plugin.Execute(serviceProvider);
                Entity targetEntity = plugin.PluginContext.PluginExecutionContext.InputParameters["Target"] as Entity;
                Account account = targetEntity.ToEntity();

                // Assert
                Assert.AreEqual("Postbank (Giro)", account.g4_bankname);
            }
        }

Zu Beginn wird der gesamte Test nun in einem ShimsContext ausgeführt. Über den ShimsContext wird die Lebensdauer der anschließend erzeugten Shims Methoden gesteuert und ist daher zwingend erforderlich.

Anschließend wird der Webservice Aufruf getBank über Shims umgebogen. Microsoft Fakes legt dabei für jeden Namespace einen untergeordneten Namespace Fakes an. Innerhalb dieses Namespaces liegen die Shim-Klassen. Wie zu sehen ist wurde zu der Original Webservice Klasse BLZServicePortTypeClient eine Shim-Klasse ShimBLZServicePortTypeClient. Um nun einen Aufruf umzubiegen und nicht mehr den Webservices aufzurufen findent sich unterhalb des statischen Members AllInstances dieser Shim-Klasse der Delegate „getBankString“. Weist man dieser Klasse nun eine Funktion zu (wie in unserem Falll eine Lambda Expression) wird statt der originalen Funktion diese Lambda Expression aufgerufen.

Auf gleiche Weise lässt sich auch jede andere Funktion ändern. Würde Beispielsweise eine Fakes Assembly für die System DLL generiert wäre es möglich auf folgende Art und Weise die DateTime.Now Funktion umgebogen:

        System.Fakes.ShimDateTime.NowGet = () =>
        {
            return new DateTime(2001, 1, 1);
        };

Anschließend würde DateTime.Now immer den 1.1.2001 zurückgeben.

Fazit
Über das Microsoft Fakes Framework ist es auf einfache Weise möglich externe Funktionen umzubiegen um korrekte Testdaten zu erhalten und dabei gleichzeitig externe Abhängigkeiten des UnitTests aufzulösen.

Der Test unseres Beispiels ist nun vollständig isoliert und erfüllt damit alle Anforderungen an einen Unit Test.

Selbstverständlich ist das Microsoft Fakes Framework dabei nicht nur auf Unit Tests für Dynamics CRM 2013 beschränkt sondern lässt sich allgemein für Unit Tests nutzen.



Diesen Blogeintrag bewerten:

5 Stimmen mit durchschnittlich 3/5 Punkten

Haben Sie Fragen zu diesem Artikel oder brauchen Sie Unterstützung?

Nehmen Sie mit uns Kontakt auf!

Wir unterstützen Sie gerne bei Ihren Vorhaben!


Schreibe einen Kommentar

Kontakt.
Lassen Sie sich von uns beraten
Wir freuen uns über Ihr Interesse an unseren Leistungen. Hinterlassen Sie
uns Ihren Namen, Ihre Telefonnummer und E-Mail Adresse – wir melden
uns schnellstmöglich bei Ihnen.
Kontakt aufnehmen