Komponententests in Office-Add-Ins

Komponententests überprüfen die Funktionalität Ihres Add-Ins, ohne dass Netzwerk- oder Dienstverbindungen erforderlich sind, einschließlich Verbindungen mit der Office-Anwendung. Serverseitiger Code für Komponententests und clientseitiger Code, der dieOffice-JavaScript-APIs nicht aufruft, sind in Office-Add-Ins identisch mit allen Webanwendungen, sodass keine spezielle Dokumentation erforderlich ist. Clientseitiger Code, der die Office-JavaScript-APIs aufruft, ist jedoch schwierig zu testen. Um diese Probleme zu lösen, haben wir eine Bibliothek erstellt, um die Erstellung von Simulierten Office-Objekten in Komponententests zu vereinfachen: Office-Addin-Mock. Die Bibliothek erleichtert das Testen auf folgende Weise:

  • Die Office-JavaScript-APIs müssen in einem Webview-Steuerelement im Kontext einer Office-Anwendung (Excel, Word usw.) initialisiert werden, damit sie nicht in den Prozess geladen werden können, in dem Komponententests auf Ihrem Entwicklungscomputer ausgeführt werden. Die Office-Addin-Mock-Bibliothek kann in Ihre Testdateien importiert werden, was das Simulieren von Office-JavaScript-APIs innerhalb des Node.js Prozesses ermöglicht, in dem die Tests ausgeführt werden.
  • Die anwendungsspezifischen APIs verfügen über Lade- und Synchronisierungsmethoden , die relativ zu anderen Funktionen und zueinander in einer bestimmten Reihenfolge aufgerufen werden müssen. Darüber hinaus muss die load -Methode mit bestimmten Parametern aufgerufen werden, je nachdem, welche Eigenschaften von Office-Objekten später in der zu testierenden Funktion vom Code gelesen werden. Komponententestframeworks sind jedoch inhärent zustandslos, sodass sie nicht aufzeichnen können, ob load oder sync aufgerufen wurde oder welche Parameter an loadübergeben wurden. Die Modellobjekte, die Sie mit der Office-Addin-Mock-Bibliothek erstellen, verfügen über einen internen Zustand, der diese Elemente nachverfolgt. Dadurch können die Pseudoobjekte das Fehlerverhalten tatsächlicher Office-Objekte emulieren. Wenn die getestete Funktion beispielsweise versucht, eine Eigenschaft zu lesen, die nicht zuerst an loadübergeben wurde, gibt der Test einen Fehler zurück, der dem ähnelt, was Office zurückgeben würde.

Die Bibliothek ist nicht von den Office JavaScript-APIs abhängig und kann mit jedem JavaScript-Komponententestframework verwendet werden, z. B.:

In den Beispielen in diesem Artikel wird das Jest-Framework verwendet. Beispiele zur Verwendung des Mocha-Frameworks gibt es auf der Office-Addin-Mock-Startseite.

Voraussetzungen

In diesem Artikel wird davon ausgegangen, dass Sie mit den grundlegenden Konzepten von Komponententests und -mocking, einschließlich des Erstellens und Ausführens von Testdateien, vertraut sind und über einige Erfahrung mit einem Komponententestframework verfügen.

Tipp

Wenn Sie mit Visual Studio arbeiten, empfiehlt es sich, den Artikel Komponententests von JavaScript und TypeScript in Visual Studio zu lesen, um einige grundlegende Informationen zu JavaScript-Komponententests in Visual Studio zu erhalten und dann zu diesem Artikel zurückzukehren.

Installieren des Tools

Öffnen Sie zum Installieren der Bibliothek eine Eingabeaufforderung, navigieren Sie zum Stammverzeichnis Ihres Add-In-Projekts, und geben Sie dann den folgenden Befehl ein.

npm install office-addin-mock --save-dev

Grundlegende Nutzung

  1. Ihr Projekt verfügt über eine oder mehrere Testdateien. (Die Anweisungen für Ihr Testframework und die Beispieltestdateien finden Sie unten in den Beispielen.) Importieren Sie die Bibliothek entweder mit dem require Schlüsselwort (keyword) oder import in eine beliebige Testdatei, die einen Test einer Funktion enthält, die die Office JavaScript-APIs aufruft, wie im folgenden Beispiel gezeigt.

    const OfficeAddinMock = require("office-addin-mock");
    
  2. Importieren Sie das Modul, das die Add-In-Funktion enthält, die Sie mit oder requireimport Schlüsselwort (keyword) testen möchten. Im folgenden Beispiel wird davon ausgegangen, dass sich Ihre Testdatei in einem Unterordner des Ordners mit den Codedateien Ihres Add-Ins befindet.

    const myOfficeAddinFeature = require("../my-office-add-in");
    
  3. Erstellen Sie ein Datenobjekt mit den Eigenschaften und Untereigenschaften, die Sie zum Testen der Funktion simulieren müssen. Im Folgenden finden Sie ein Beispiel für ein Objekt, das die Excel Workbook.range.address-Eigenschaft und die Workbook.getSelectedRange-Methode simuliert. Dies ist nicht das letzte Pseudoobjekt. Stellen Sie sich dies als Seedobjekt vor, das von OfficeMockObject zum Erstellen des endgültigen Pseudoobjekts verwendet wird.

    const mockData = {
      workbook: {
        range: {
          address: "C2:G3",
        },
        getSelectedRange: function () {
          return this.range;
        },
      },
    };
    
  4. Übergeben Sie das Datenobjekt an den OfficeMockObject Konstruktor. Beachten Sie Folgendes zum zurückgegebenen OfficeMockObject Objekt.

    • Es handelt sich um ein vereinfachtes Modell eines OfficeExtension.ClientRequestContext-Objekts .
    • Das Mockobjekt verfügt über alle Member des Datenobjekts und verfügt auch über Pseudoimplementierungen der load Methoden und sync .
    • Das Pseudoobjekt imitiert das entscheidende Fehlerverhalten des ClientRequestContext Objekts. Wenn die Office-API, die Sie testen, z. B. versucht, eine Eigenschaft zu lesen, ohne zuerst die Eigenschaft zu laden und aufzurufen sync, schlägt der Test mit einem Fehler fehl, der dem ähnelt, was in der Produktionslaufzeit ausgelöst wird: "Fehler, Eigenschaft nicht geladen".
    const contextMock = new OfficeAddinMock.OfficeMockObject(mockData);
    

    Hinweis

    Die vollständige Referenzdokumentation für den OfficeMockObject Typ finden Sie unter Office-Addin-Mock.

  5. Fügen Sie in der Syntax Ihres Testframeworks einen Test der Funktion hinzu. Verwenden Sie das OfficeMockObject -Objekt anstelle des Objekts, das es simuliert, in diesem Fall das ClientRequestContext -Objekt. Im Folgenden wird das Beispiel in Jest fortgesetzt. Bei diesem Beispieltest wird davon ausgegangen, dass die zu testende Add-In-Funktion den Namen trägt getSelectedRangeAddress, dass sie ein ClientRequestContext -Objekt als Parameter akzeptiert und die Adresse des aktuell ausgewählten Bereichs zurückgeben soll. Das vollständige Beispiel finden Sie weiter unten in diesem Artikel.

    test("getSelectedRangeAddress should return the address of the range", async function () {
      expect(await getSelectedRangeAddress(contextMock)).toBe("C2:G3");
    });
    
  6. Führen Sie den Test gemäß der Dokumentation des Testframeworks und Ihrer Entwicklungstools aus. In der Regel gibt es eine Package.json-Datei mit einem Skript, das das Testframework ausführt. Wenn z. B. Jest das Framework ist, enthält package.json Folgendes:

    "scripts": {
      "test": "jest",
      -- other scripts omitted --  
    }
    

    Um den Test auszuführen, geben Sie Folgendes in einer Eingabeaufforderung im Stammverzeichnis des Projekts ein.

    npm test
    

Beispiele

In den Beispielen in diesem Abschnitt wird Jest mit den Standardeinstellungen verwendet. Diese Einstellungen unterstützen CommonJS-Module. Informationen zum Konfigurieren von Jest und Node.js zur Unterstützung von ECMAScript-Modulen und zur Unterstützung von TypeScript finden Sie in der Jest-Dokumentation . Führen Sie die folgenden Schritte aus, um eines dieser Beispiele auszuführen.

  1. Erstellen Sie ein Office-Add-In-Projekt für die entsprechende Office-Hostanwendung (z. B. Excel oder Word). Eine Möglichkeit, dies schnell zu tun, ist die Verwendung des Yeoman-Generators für Office-Add-Ins.
  2. Installieren Sie im Stammverzeichnis des Projekts Jest.
  3. Installieren Sie das Tool office-addin-mock.
  4. Erstellen Sie eine Datei genau wie die erste Datei im Beispiel, und fügen Sie sie dem Ordner hinzu, der die anderen Quelldateien des Projekts enthält, die häufig als bezeichnet werden \src.
  5. Erstellen Sie einen Unterordner für den Quelldateiordner, und geben Sie ihm einen entsprechenden Namen, z \tests. B. .
  6. Erstellen Sie eine Datei genau wie die Testdatei im Beispiel, und fügen Sie sie dem Unterordner hinzu.
  7. Fügen Sie der Datei package.json ein test Skript hinzu, und führen Sie dann den Test aus, wie unter Grundlegende Verwendung beschrieben.

Simulieren der allgemeinen Office-APIs

In diesem Beispiel wird von einem Office-Add-In für jeden Host ausgegangen, der die allgemeinen Office-APIs unterstützt (z. B. Excel, PowerPoint oder Word). Das Add-In verfügt über eines seiner Features in einer Datei namens my-common-api-add-in-feature.js. Im Folgenden wird der Inhalt der Datei veranschaulicht. Die addHelloWorldText Funktion legt den Text "Hallo Welt!" auf den aktuell im Dokument ausgewählten Text fest, z. B. auf einen Bereich in Word oder eine Zelle in Excel oder auf ein Textfeld in PowerPoint.

const myCommonAPIAddinFeature = {

    addHelloWorldText: async () => {
        const options = { coercionType: Office.CoercionType.Text };
        await Office.context.document.setSelectedDataAsync("Hello World!", options);
    }
}
  
module.exports = myCommonAPIAddinFeature;

Die Testdatei mit dem Namen my-common-api-add-in-feature.test.js befindet sich relativ zum Speicherort der Add-In-Codedatei in einem Unterordner. Im Folgenden wird der Inhalt der Datei veranschaulicht. Beachten Sie, dass die Eigenschaft der obersten Ebene ein Office.Context-Objekt istcontext, sodass das Objekt, das simuliert wird, das übergeordnete Objekt dieser Eigenschaft ist: ein Office-Objekt. Zu diesem Code ist Folgendes anzumerken:

  • Der OfficeMockObject Konstruktor fügt dem Pseudoobjekt Office nicht alle Office-Enumerationsklassen hinzu, daher muss der Wert, auf den CoercionType.Text in der Add-In-Methode verwiesen wird, explizit im Seedobjekt hinzugefügt werden.
  • Da die Office JavaScript-Bibliothek nicht im Knotenprozess geladen wird, muss das Office Objekt, auf das im Add-In-Code verwiesen wird, deklariert und initialisiert werden.
const OfficeAddinMock = require("office-addin-mock");
const myCommonAPIAddinFeature = require("../my-common-api-add-in-feature");

// Create the seed mock object.
const mockData = {
    context: {
      document: {
        setSelectedDataAsync: function (data, options) {
          this.data = data;
          this.options = options;
        },
      },
    },
    // Mock the Office.CoercionType enum.
    CoercionType: {
      Text: {},
    },
};
  
// Create the final mock object from the seed object.
const officeMock = new OfficeAddinMock.OfficeMockObject(mockData);

// Create the Office object that is called in the addHelloWorldText function.
global.Office = officeMock;

/* Code that calls the test framework goes below this line. */

// Jest test
test("Text of selection in document should be set to 'Hello World'", async function () {
    await myCommonAPIAddinFeature.addHelloWorldText();
    expect(officeMock.context.document.data).toBe("Hello World!");
});

Simulieren der Outlook-APIs

Obwohl die Outlook-APIs streng genommen Teil des allgemeinen API-Modells sind, verfügen sie über eine spezielle Architektur, die um das Mailbox-Objekt herum erstellt wurde. Daher haben wir ein eindeutiges Beispiel für Outlook bereitgestellt. In diesem Beispiel wird davon ausgegangen, dass outlook über eines seiner Features in einer Datei namens verfügt my-outlook-add-in-feature.js. Im Folgenden wird der Inhalt der Datei veranschaulicht. Die addHelloWorldText Funktion legt den Text "Hallo Welt!" auf den wert fest, der derzeit im Fenster zum Verfassen von Nachrichten ausgewählt ist.

const myOutlookAddinFeature = {

    addHelloWorldText: async () => {
        Office.context.mailbox.item.setSelectedDataAsync("Hello World!");
      }
}

module.exports = myOutlookAddinFeature;

Die Testdatei mit dem Namen my-outlook-add-in-feature.test.js befindet sich relativ zum Speicherort der Add-In-Codedatei in einem Unterordner. Im Folgenden wird der Inhalt der Datei veranschaulicht. Beachten Sie, dass die Eigenschaft der obersten Ebene ein Office.Context-Objekt istcontext, sodass das Objekt, das simuliert wird, das übergeordnete Objekt dieser Eigenschaft ist: ein Office-Objekt. Zu diesem Code ist Folgendes anzumerken:

  • Die host -Eigenschaft des Pseudoobjekts wird intern von der Modellbibliothek verwendet, um die Office-Anwendung zu identifizieren. Dies ist für Outlook obligatorisch. Es dient derzeit keinem Zweck für andere Office-Anwendungen.
  • Da die Office JavaScript-Bibliothek nicht im Knotenprozess geladen wird, muss das Office Objekt, auf das im Add-In-Code verwiesen wird, deklariert und initialisiert werden.
const OfficeAddinMock = require("office-addin-mock");
const myOutlookAddinFeature = require("../my-outlook-add-in-feature");

// Create the seed mock object.
const mockData = {
  // Identify the host to the mock library (required for Outlook).
  host: "outlook",
  context: {
    mailbox: {
      item: {
          setSelectedDataAsync: function (data) {
          this.data = data;
        },
      },
    },
  },
};
  
// Create the final mock object from the seed object.
const officeMock = new OfficeAddinMock.OfficeMockObject(mockData);

// Create the Office object that is called in the addHelloWorldText function.
global.Office = officeMock;

/* Code that calls the test framework goes below this line. */

// Jest test
test("Text of selection in message should be set to 'Hello World'", async function () {
    await myOutlookAddinFeature.addHelloWorldText();
    expect(officeMock.context.mailbox.item.data).toBe("Hello World!");
});

Simulieren der anwendungsspezifischen Office-APIs

Wenn Sie Funktionen testen, die die anwendungsspezifischen APIs verwenden, stellen Sie sicher, dass Sie den richtigen Objekttyp simulieren. Es gibt zwei Möglichkeiten:

  • Simulieren sie ein OfficeExtension.ClientRequestObject. Führen Sie dies aus, wenn die getestete Funktion die beiden folgenden Bedingungen erfüllt:

    • Es ruft keinen Host auf.run -Funktion, z. B. Excel.run.
    • Es verweist nicht auf eine andere direkte Eigenschaft oder Methode eines Host-Objekts .
  • Simulieren sie ein Host-Objekt, z. B. Excel oder Word. Gehen Sie dazu vor, wenn die vorherige Option nicht möglich ist.

Beispiele für beide Arten von Tests finden Sie in den folgenden Unterabschnitten.

Hinweis

Die Office-Addin-Mock-Bibliothek unterstützt derzeit keine Mocking von Auflistungstypobjekten, bei denen es sich um objekte in den anwendungsspezifischen APIs handelt, die nach dem Muster *Collection benannt sind, z. B. WorksheetCollection. Wir arbeiten hart daran, diese Unterstützung zur Bibliothek hinzuzufügen.

Simulieren eines ClientRequestContext-Objekts

In diesem Beispiel wird davon ausgegangen, dass ein Excel-Add-In über eines seiner Features in einer Datei namens verfügt my-excel-add-in-feature.js. Im Folgenden wird der Inhalt der Datei veranschaulicht. Beachten Sie, dass es sich bei um getSelectedRangeAddress eine Hilfsmethode namens innerhalb des Rückrufs handelt, der an Excel.runübergeben wird.

const myExcelAddinFeature = {
    
    getSelectedRangeAddress: async (context) => {
        const range = context.workbook.getSelectedRange();      
        range.load("address");

        await context.sync();
      
        return range.address;
    }
}

module.exports = myExcelAddinFeature;

Die Testdatei mit dem Namen my-excel-add-in-feature.test.js befindet sich relativ zum Speicherort der Add-In-Codedatei in einem Unterordner. Im Folgenden wird der Inhalt der Datei veranschaulicht. Beachten Sie, dass die Eigenschaft der obersten Ebene ist workbook, sodass das Objekt, das simuliert wird, das übergeordnete Objekt eines Excel.Workbookist: ein ClientRequestContext -Objekt.

const OfficeAddinMock = require("office-addin-mock");
const myExcelAddinFeature = require("../my-excel-add-in-feature");

// Create the seed mock object.
const mockData = {
    workbook: {
      range: {
        address: "C2:G3",
      },
      // Mock the Workbook.getSelectedRange method.
      getSelectedRange: function () {
        return this.range;
      },
    },
};

// Create the final mock object from the seed object.
const contextMock = new OfficeAddinMock.OfficeMockObject(mockData);

/* Code that calls the test framework goes below this line. */

// Jest test
test("getSelectedRangeAddress should return address of selected range", async function () {
  expect(await myOfficeAddinFeature.getSelectedRangeAddress(contextMock)).toBe("C2:G3");
});

Simulieren eines Hostobjekts

In diesem Beispiel wird davon ausgegangen, dass ein Word-Add-In über eines seiner Features in einer Datei namens verfügtmy-word-add-in-feature.js. Im Folgenden wird der Inhalt der Datei veranschaulicht.

const myWordAddinFeature = {

  insertBlueParagraph: async () => {
    return Word.run(async (context) => {
      // Insert a paragraph at the end of the document.
      const paragraph = context.document.body.insertParagraph("Hello World", Word.InsertLocation.end);
  
      // Change the font color to blue.
      paragraph.font.color = "blue";
  
      await context.sync();
    });
  }
}

module.exports = myWordAddinFeature;

Die Testdatei mit dem Namen my-word-add-in-feature.test.js befindet sich relativ zum Speicherort der Add-In-Codedatei in einem Unterordner. Im Folgenden wird der Inhalt der Datei veranschaulicht. Beachten Sie, dass die Eigenschaft der obersten Ebene ein ClientRequestContext -Objekt istcontext, sodass das Objekt, das simuliert wird, das übergeordnete Objekt dieser Eigenschaft ist: ein Word -Objekt. Zu diesem Code ist Folgendes anzumerken:

  • Wenn der OfficeMockObject Konstruktor das letzte Pseudoobjekt erstellt, wird sichergestellt, dass das untergeordnete ClientRequestContext Objekt sync über - und load -Methoden verfügt.
  • Der OfficeMockObject Konstruktor fügt run dem Pseudoobjekt Wordkeine Funktion hinzu, daher muss sie explizit im Seedobjekt hinzugefügt werden.
  • Der OfficeMockObject Konstruktor fügt dem Pseudoobjekt Word nicht alle Word Enumerationsklassen hinzu, sodass der Wert, auf den InsertLocation.end in der Add-In-Methode verwiesen wird, explizit im Seedobjekt hinzugefügt werden muss.
  • Da die Office JavaScript-Bibliothek nicht im Knotenprozess geladen wird, muss das Word Objekt, auf das im Add-In-Code verwiesen wird, deklariert und initialisiert werden.
const OfficeAddinMock = require("office-addin-mock");
const myWordAddinFeature = require("../my-word-add-in-feature");

// Create the seed mock object.
const mockData = {
  context: {
    document: {
      body: {
        paragraph: {
          font: {},
        },
        // Mock the Body.insertParagraph method.
        insertParagraph: function (paragraphText, insertLocation) {
          this.paragraph.text = paragraphText;
          this.paragraph.insertLocation = insertLocation;
          return this.paragraph;
        },
      },
    },
  },
  // Mock the Word.InsertLocation enum.
  InsertLocation: {
    end: "end",
  },
  // Mock the Word.run function.
  run: async function(callback) {
    await callback(this.context);
  },
};

// Create the final mock object from the seed object.
const wordMock = new OfficeAddinMock.OfficeMockObject(mockData);

// Define and initialize the Word object that is called in the insertBlueParagraph function.
global.Word = wordMock;

/* Code that calls the test framework goes below this line. */

// Jest test set
describe("Insert blue paragraph at end tests", () => {

  test("color of paragraph", async function () {
    await myWordAddinFeature.insertBlueParagraph();  
    expect(wordMock.context.document.body.paragraph.font.color).toBe("blue");
  });

  test("text of paragraph", async function () {
    await myWordAddinFeature.insertBlueParagraph();
    expect(wordMock.context.document.body.paragraph.text).toBe("Hello World");
  });
})

Hinweis

Die vollständige Referenzdokumentation für den OfficeMockObject Typ finden Sie unter Office-Addin-Mock.

Siehe auch