Share via


Office アドインでの単体テスト

単体テストでは、Office アプリケーションへの接続など、ネットワーク接続やサービス接続を必要とせずに、アドインの機能をチェックします。 サーバー側の単体テスト コードと、Office JavaScript API を呼び出さないクライアント側コードは、Office アドインの場合とどの Web アプリケーションでも同じであるため、特別なドキュメントは必要ありません。 ただし、Office JavaScript API を呼び出すクライアント側のコードは、テストが困難です。 これらの問題を解決するために、単体テストでのモック Office オブジェクトの作成を簡略化するライブラリを作成しました: Office-Addin-Mock。 ライブラリを使用すると、次の方法でテストが容易になります。

  • Office JavaScript API は、Office アプリケーション (Excel、Word など) のコンテキストで Webview コントロールで初期化する必要があるため、開発用コンピューターで単体テストを実行するプロセスに読み込むことができません。 Office-Addin-Mock ライブラリをテスト ファイルにインポートできます。これにより、テストを実行する Node.js プロセス内で Office JavaScript API をモックできます。
  • アプリケーション固有の API には、他の関数と相互に対して特定の順序で呼び出す必要がある読み込みおよび同期メソッドがあります。 さらに、テスト対象の load 関数の 後半 でコードによって読み込まれる Office オブジェクトのプロパティに応じて、メソッドを特定のパラメーターで呼び出す必要があります。 ただし、単体テスト フレームワークは本質的にステートレスであるため、呼び出されたか、どのsyncパラメーターが にload渡されたかを記録loadすることはできません。 Office-Addin-Mock ライブラリを使用して作成するモック オブジェクトには、これらのことを追跡する内部状態があります。 これにより、モック オブジェクトは、実際の Office オブジェクトのエラー動作をエミュレートできます。 たとえば、テスト対象の関数が、 に最初に渡されなかった loadプロパティを読み取ろうとすると、テストは Office から返されるエラーと同様のエラーを返します。

ライブラリは Office JavaScript API に依存せず、次のような任意の JavaScript 単体テスト フレームワークで使用できます。

この記事の例では、Jest フレームワークを使用します。 Office-Addin-Mock ホーム ページで Mocha フレームワークを使用する例があります。

前提条件

この記事では、テスト ファイルを作成して実行する方法など、単体テストとモックの基本的な概念に精通していること、および単体テスト フレームワークに関する経験があることを前提としています。

ヒント

Visual Studio を使用している場合は、Visual Studio での JavaScript 単体テストに関する基本的な情報については、 Visual Studio での JavaScript と TypeScript の単体テスト に関する記事を読み、この記事に戻ってください。

ツールをインストールする

ライブラリをインストールするには、コマンド プロンプトを開き、アドイン プロジェクトのルートに移動し、次のコマンドを入力します。

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

基本的な使用法

  1. プロジェクトには、1 つ以上のテスト ファイルがあります。 (以下の例では、テスト フレームワークの手順とテスト ファイルの例を参照してください)。次の例に示すように、 または import キーワード (keyword) をrequire使用して、Office JavaScript API を呼び出す関数のテストがあるテスト ファイルにライブラリをインポートします。

    const OfficeAddinMock = require("office-addin-mock");
    
  2. または import キーワード (keyword) でテストするアドイン関数を含むモジュールをrequireインポートします。 次の例では、テスト ファイルがアドインのコード ファイルを含むフォルダーのサブフォルダー内にあることを前提としています。

    const myOfficeAddinFeature = require("../my-office-add-in");
    
  3. 関数をテストするためにモックする必要があるプロパティとサブプロパティを持つデータ オブジェクトを作成します。 Excel Workbook.range.address プロパティと Workbook.getSelectedRange メソッドをモックするオブジェクトの例を次に示します。 これは最終的なモック オブジェクトではありません。 最終的なモック オブジェクトを作成するために使用 OfficeMockObject されるシード オブジェクトと考えてください。

    const mockData = {
      workbook: {
        range: {
          address: "C2:G3",
        },
        getSelectedRange: function () {
          return this.range;
        },
      },
    };
    
  4. コンストラクターにデータ オブジェクトを OfficeMockObject 渡します。 返されるオブジェクトについては、次の点に OfficeMockObject 注意してください。

    • これは、 OfficeExtension.ClientRequestContext オブジェクトの簡略化されたモックです。
    • モック オブジェクトには、データ オブジェクトのすべてのメンバーがあり、 メソッドと sync メソッドのloadモック実装もあります。
    • モック オブジェクトは、オブジェクトの重要なエラー動作を ClientRequestContext 模倣します。 たとえば、テスト中の Office API がプロパティを読み込んで を呼び出 syncさずにプロパティを読み取ろうとした場合、テストは、運用環境の実行時にスローされるエラーと同様のエラーで失敗します。"エラー、プロパティが読み込まれていません" です。
    const contextMock = new OfficeAddinMock.OfficeMockObject(mockData);
    

    注:

    この型の OfficeMockObject 完全なリファレンス ドキュメントは 、Office-Addin-Mock にあります

  5. テスト フレームワークの構文で、 関数のテストを追加します。 モックする OfficeMockObject オブジェクトの代わりに オブジェクト (この場合は オブジェクト) を ClientRequestContext 使用します。 Jest の例を次に示します。 このテスト例では、テスト対象のアドイン関数が と呼ばれ getSelectedRangeAddress、オブジェクトをパラメーターとして受け取り ClientRequestContext 、現在選択されている範囲のアドレスを返すことを想定しています。 完全な例については、 この記事の後半で説明します

    test("getSelectedRangeAddress should return the address of the range", async function () {
      expect(await getSelectedRangeAddress(contextMock)).toBe("C2:G3");
    });
    
  6. テスト フレームワークと開発ツールのドキュメントに従ってテストを実行します。 通常、テスト フレームワークを実行するスクリプトを含む package.json ファイルがあります。 たとえば、Jest がフレームワークの場合、 package.json には次のものが含まれます。

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

    テストを実行するには、プロジェクトのルートにあるコマンド プロンプトに次のように入力します。

    npm test
    

このセクションの例では、既定の設定で Jest を使用します。 これらの設定では、CommonJS モジュールがサポートされています。 ECMAScript モジュールをサポートし、TypeScript をサポートするように Jest と Node.js を構成する方法については、 Jest のドキュメントを参照してください 。 これらの例のいずれかを実行するには、次の手順を実行します。

  1. 適切な Office ホスト アプリケーション (Excel やWordなど) の Office アドイン プロジェクトを作成します。 これを迅速に行う方法の 1 つは、 Office アドイン用の Yeoman ジェネレーターを使用することです。
  2. プロジェクトのルートに Jest をインストールします。
  3. office-addin-mock ツールをインストールします。
  4. 例の最初のファイルとまったく同じようにファイルを作成し、プロジェクトの他のソース ファイル (多くの場合、 と呼ばれる \src) を含むフォルダーに追加します。
  5. ソース ファイル フォルダーのサブフォルダーを作成し、 などの \tests適切な名前を付けます。
  6. 例のテスト ファイルとまったく同じファイルを作成し、サブフォルダーに追加します。
  7. testpackage.json ファイルにスクリプトを追加し、「基本的な使用法」で説明されているようにテストを実行します。

Office 共通 API のモック作成

この例では、Office Common API (Excel、PowerPoint、Word など) をサポートするすべてのホストの Office アドインを想定しています。 アドインには、 という名前 my-common-api-add-in-feature.jsのファイル内の機能の 1 つがあります。 ファイルの内容を次に示します。 この関数はaddHelloWorldText、ドキュメントで現在選択されている内容 (たとえば、Wordの範囲、Excel のセル、PowerPoint のテキスト ボックスなど) にテキスト "Hello World!" を設定します。

const myCommonAPIAddinFeature = {

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

という名前 my-common-api-add-in-feature.test.js のテスト ファイルは、アドイン コード ファイルの場所を基準にしてサブフォルダー内にあります。 ファイルの内容を次に示します。 最上位のプロパティは contextOffice.Context オブジェクトであるため、モックされるオブジェクトは、このプロパティの親である Office オブジェクトです。 このコードについては、次の点に注意してください。

  • コンストラクターはすべての OfficeMockObject Office 列挙型クラスをモック Office オブジェクトに追加するわけではありません。そのためCoercionType.Text、アドイン メソッドで参照される値はシード オブジェクトに明示的に追加する必要があります。
  • Office JavaScript ライブラリはノード プロセスに読み込まれていないため、 Office アドイン コードで参照されるオブジェクトを宣言して初期化する必要があります。
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!");
});

Outlook API のモック作成

厳密に言えば、Outlook API は共通 API モデルの一部ですが、 Mailbox オブジェクトを中心に構築された特殊なアーキテクチャがあるため、Outlook の明確な例を提供しています。 この例では、 という名前 my-outlook-add-in-feature.jsのファイルに機能の 1 つを含む Outlook を想定しています。 ファイルの内容を次に示します。 関数はaddHelloWorldText、メッセージ作成ウィンドウで現在選択されている内容にテキスト "Hello World!" を設定します。

const myOutlookAddinFeature = {

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

module.exports = myOutlookAddinFeature;

という名前 my-outlook-add-in-feature.test.js のテスト ファイルは、アドイン コード ファイルの場所を基準にしてサブフォルダー内にあります。 ファイルの内容を次に示します。 最上位のプロパティは contextOffice.Context オブジェクトであるため、モックされるオブジェクトは、このプロパティの親である Office オブジェクトです。 このコードについては、次の点に注意してください。

  • モック オブジェクトのプロパティは host 、モック ライブラリによって内部的に使用され、Office アプリケーションを識別します。 Outlook では必須です。 現在、他の Office アプリケーションの目的は果たしません。
  • Office JavaScript ライブラリはノード プロセスに読み込まれていないため、 Office アドイン コードで参照されるオブジェクトを宣言して初期化する必要があります。
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!");
});

Office アプリケーション固有の API をモックする

アプリケーション固有の API を使用する関数をテストする場合は、適切な種類のオブジェクトをモックしていることを確認してください。 次のような 2 つのオプションがあります。

  • OfficeExtension.ClientRequestObject をモックします。 これは、テスト対象の関数が次の両方の条件を満たしている場合に行います。

    • ホストは呼び出しません。run 関数 ( Excel.run など)。
    • Host オブジェクトの他の直接プロパティまたはメソッドは参照しません。
  • ExcelWord などの Host オブジェクトをモックします。 上記のオプションが不可能な場合は、これを行います。

両方の種類のテストの例は、以下のサブセクションにあります。

注:

Office-Addin-Mock ライブラリでは、現在、コレクション型オブジェクトのモックはサポートされていません。これは、WorksheetCollection などのパターン *Collection に名前が付けられたアプリケーション固有の API 内のすべてのオブジェクトです。 このサポートをライブラリに追加するために一生懸命取り組んでいます。

ClientRequestContext オブジェクトをモックする

この例では、 という名前 my-excel-add-in-feature.jsのファイルに機能の 1 つを含む Excel アドインを想定しています。 ファイルの内容を次に示します。 は、 に渡されるコールバック内で呼び出されるExcel.runヘルパー メソッドであることにgetSelectedRangeAddress注意してください。

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

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

module.exports = myExcelAddinFeature;

という名前 my-excel-add-in-feature.test.js のテスト ファイルは、アドイン コード ファイルの場所を基準にしてサブフォルダー内にあります。 ファイルの内容を次に示します。 最上位のプロパティは workbookです。そのため、モックされているオブジェクトは、 オブジェクトClientRequestContextExcel.Workbook親になります。

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");
});

ホスト オブジェクトのモック化

この例では、 という名前my-word-add-in-feature.jsのファイルに機能の 1 つを含むWord アドインを想定しています。 ファイルの内容を次に示します。

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;

という名前 my-word-add-in-feature.test.js のテスト ファイルは、アドイン コード ファイルの場所を基準にしてサブフォルダー内にあります。 ファイルの内容を次に示します。 最上位のプロパティは contextClientRequestContext オブジェクトであるため、モックされるオブジェクトはこのプロパティ Word の親である オブジェクトであることに注意してください。 このコードについては、次の点に注意してください。

  • コンストラクターは、 OfficeMockObject 最終的なモック オブジェクトを作成するときに、子 ClientRequestContext オブジェクト sync に と load メソッドがあることを確認します。
  • コンストラクターはOfficeMockObjectモック Word オブジェクトに関数を追加runしないため、シード オブジェクトに明示的に追加する必要があります。
  • コンストラクターではOfficeMockObject、Word列挙型クラスがすべてモック Word オブジェクトに追加されるわけではありません。そのためInsertLocation.end、アドイン メソッドで参照される値はシード オブジェクトに明示的に追加する必要があります。
  • Office JavaScript ライブラリはノード プロセスに読み込まれていないため、 Word アドイン コードで参照されるオブジェクトを宣言して初期化する必要があります。
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");
  });
})

注:

この型の OfficeMockObject 完全なリファレンス ドキュメントは 、Office-Addin-Mock にあります

関連項目