Table of Contents

Testautomatisierung in Extensions

In Kundenprojekten skalieren Fehler im Quellcode grundsätzlich anders, als im Standardcode von Business Central oder in Apps wie unitop. Dies liegt an der Anzahl der potentiellen Installationen (in der Regel genau eine) sowie der typischerweise vergleichsweise geringen Prozesstiefe vieler Individualanpassungen.

Daher gelten für automatisierte Tests in Projekten folgende Leitlinien:

  • Tests müssen wirtschaftlich sein
  • Tests müssen Kernprozesse absichern
  • Tests können Nebenprozesse absichern, wenn sie dabei wirtschaftlich sind

Ein Test ist dann wirtschaftlich, wenn eine der folgenden Bedingungen erfüllt ist. Es ist in der Praxis oft so, dass auf eine betrachtete Funktionalität mehrere Aspekte zutreffen:

  • Test-driven Development beschleunigt die Entwicklungszeit, der oder die Tests entstehen ohnehin bei der primären Entwicklung. Dies ist oft der Fall in Funktionalitäten,
    • für die komplexe Datenaufbereitung zum manuellen Testen erforderlich ist
    • oder bei denen aufgrund hoher Komplexität die Umsetzung mit Unsicherheit behaftet ist
  • Die Funktionalität erstreckt sich über viele Schritte und Komponenten, deren Integration sicherzustellen aufwändige Nacharbeiten verhindert. Dies ist oft der Fall, wenn die einzelnen Bestandteile eines Prozesses eigenständige Lebenszyklen haben und ohne automatisierten Test nie klar ist, ob der Prozess (noch) funktioniert.
  • Die Funktionalität hat sich als fehleranfällig erwiesen. Mit dem Bugfixing können zugleich durch den automatisierten Test zukünftige Nacharbeiten eingedämmt werden.

Kernprozesse sind die Prozesse des Kunden, bei dessen Ausfall er sein Kerngeschäft nicht abwickeln kann. Oft fallen diese Prozesse ohnehin auch in die Definition der Wirtschaftlichkeit.

Hinweis

Aktuell sind automatisierte Tests für Kundenprojekte empfohlen, aber nicht verpflichtend vorgeschrieben. Die Qualitätssicherung kann auch durch manuelle Tests erfolgen. Im Projekt legt die Entwicklungsleitung oder der zuständige Lead Developer die Nutzung fest.

Technische Organisation

Tests für eine Extension werden in eigenen Extensions bereitgestellt. Die Test Extension wird wie die produktiven Extensions in einem eigenen Ordner im Workspace bereitgestellt und hat dort folgenden Ordnernamen:

[NAME DER EXTENSION][ ]Test

Also z. B.: Meine Extension Test

Die Test Extension folgt allen sonstigen Vorgaben zur Struktur. Zuzüglich dazu hat sie eine Abhängigkeit von der zu testenden Extension und normalerweise keine weiteren Abhängigkeiten. Eine Ausnahme stellen Abhängigkeiten zu Test Apps von Microsoft und ggf. unitop dar - diese sind immer erlaubt.

Aufbau von Tests

Tests werden in Codeunits geschrieben und folgen dem Feature/Scenario/Given/When/Then-Schema.

  • // [Feature] beschreibt das Feature für das die gesamte Test Codeunit ausgelegt ist.
  • // [Scenario] beschreibt das konkrete Szenario in der einzelnen Testfunktion
  • // [Given] beschreibt (ggf. in mehreren Kommentaren) den Ausgangszustand des Szenarios. Es folgen dann die Funktionen die den Zustand dann herstellen.
  • // [When] beschreibt (ggf. in mehreren Kommentaren) den Ablauf des Szenarios. Es folgen jeweils die konkreten Funktionen.
  • // [Then] beschreibt (ggf. in mehreren Kommentaren) das erwartete Ergebnis. Es folgen jeweils die Prüfungen ob der erwartete Zustand erreicht wurde.

Anbei ein Beispiel aus unitop:

codeunit 50101 "GOB Webservice Management Test"
{
    // [FEATURE] [GOB Webservice Management]
    Subtype = Test;

    trigger OnRun()
    begin
    end;

    var
        Manager: Codeunit "GOB Webservice Management";
        Mock: Codeunit "GOB Webservice Comm. Mock";
        ResponseGen: Codeunit "GOB Webservice Mock Resp. Gen.";
        ExpCodeTxt: Label '1234';
        ExpMsgTxt: Label 'Error';
        ExpectedResponse: Text;

    [Test]
    procedure TestTrialIsCreated()
    var
        Assert: Codeunit Assert;
        CustomerId: Text;
        State: Boolean;
        ExpCustIdTxt: Label 'E68C256B-EDB8-4E11-B070-FB56FCD9D260';
    begin
        // [Scenario] Start a trial period for a feature app
        // [Given] The trial is started successful

        Setup();
        ResponseGen.CreateTrialSuccessResponse(ExpCustIdTxt, ExpectedResponse);
        Mock.AddResponseWithContent(Mock.StartTrialUrl(), ExpectedResponse, 200, true);

        // [When] CreateTrial is called
        State := Manager.CreateTrial('3a765acd-18ca-4810-a0de-e48aaa756792', '40716111-e229-4294-abd3-8845c0a88568', true, CustomerId);

        // [Then] CreateTrial should return true
        Assert.IsTrue(State, 'Request failed');
        // [Then] CreateTrial should write the customer id contained in the response to CustomerId
        Assert.AreEqual(ExpCustIdTxt, CustomerId, 'CustomerId not set correctly');
        // [Then] LastHttpStatusCode should be set
        Assert.AreEqual(200, Manager.GetLastHttpStatusCode(), 'Http status not set correctly');
    end;