Поделиться через


Модульное тестирование в надстройках Office

Модульные тесты проверка функциональные возможности надстройки, не требуя подключения к сети или службе, включая подключения к приложению Office. Код на стороне сервера модульного тестирования и код на стороне клиента, который не вызывает API JavaScript для Office, в надстройках Office так же, как и в любом веб-приложении, поэтому для него не требуется специальная документация. Но клиентский код, который вызывает API JavaScript для Office, сложно протестировать. Для решения этих проблем мы создали библиотеку для упрощения создания макетных объектов Office в модульных тестах : Office-Addin-Mock. Библиотека упрощает тестирование следующими способами:

  • API JavaScript для Office должны инициализироваться в элементе управления webview в контексте приложения Office (Excel, Word и т. д.), поэтому их нельзя загрузить в процессе выполнения модульных тестов на компьютере разработки. Библиотеку Office-Addin-Mock можно импортировать в тестовые файлы, что позволяет макетировать API JavaScript для Office внутри Node.js процесса, в котором выполняются тесты.
  • Api-интерфейсы приложений имеют методы загрузки и синхронизации, которые должны вызываться в определенном порядке относительно других функций и друг к другу. Кроме того, метод должен вызываться с определенными параметрами в зависимости от того, load какие свойства объектов Office будут считываться в коде позже в тестируемой функции. Но платформы модульного тестирования по своей сути не поддерживают отслеживание состояния, поэтому они не могут вести запись о том, был ли load вызван или sync был вызван или какие параметры были переданы в load. Макетные объекты, создаваемые с помощью библиотеки Office-Addin-Mock, имеют внутреннее состояние, которое отслеживает эти вещи. Это позволяет макетным объектам эмулировать поведение фактических объектов Office с ошибками. Например, если проверяемая функция пытается считывать свойство, которое не было сначала передано loadв , то тест вернет ошибку, аналогичную той, которая будет возвращена Office.

Библиотека не зависит от API JavaScript для Office, и ее можно использовать с любой платформой модульного тестирования JavaScript, например:

В примерах, приведенных в этой статье, используется платформа Jest. Примеры использования платформы Mocha приведены на домашней странице Office-Addin-Mock.

Предварительные требования

В этой статье предполагается, что вы знакомы с основными понятиями модульного тестирования и макетирования, включая создание и запуск тестовых файлов, и что у вас есть некоторый опыт работы с платформой модульного тестирования.

Совет

Если вы работаете с Visual Studio, мы рекомендуем прочитать статью Модульное тестирование JavaScript и TypeScript в Visual Studio , чтобы получить некоторые основные сведения о модульном тестировании JavaScript в Visual Studio, а затем вернуться к этой статье.

Установка средства

Чтобы установить библиотеку, откройте командную строку, перейдите в корневой каталог проекта надстройки и введите следующую команду.

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

Базовое использование

  1. Проект будет содержать один или несколько тестовых файлов. (См. инструкции для платформы тестирования и примеры файлов тестов в разделе Примеры ниже.) Импортируйте библиотеку с помощью require или import ключевое слово в любой тестовый файл, который содержит тест функции, которая вызывает API JavaScript для Office, как показано в следующем примере.

    const OfficeAddinMock = require("office-addin-mock");
    
  2. Импортируйте модуль, содержащий функцию надстройки, которую необходимо протестировать с помощью require или import ключевое слово. Ниже приведен пример, в который предполагается, что тестовый файл находится во вложенной папке папки с файлами кода надстройки.

    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 .
    • Объект макета содержит все члены объекта данных, а также макетные load реализации методов и sync .
    • Макет объекта будет имитировать поведение объекта с критическими ошибками ClientRequestContext . Например, если тестируемый API Office пытается прочитать свойство без предварительной загрузки свойства и вызова 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. Сведения о настройке Jest и Node.js для поддержки модулей ECMAScript и поддержки TypeScript см. в документации по Jest . Чтобы выполнить любой из этих примеров, выполните следующие действия.

  1. Создайте проект надстройки Office для соответствующего ведущего приложения Office (например, Excel или Word). Один из способов быстро сделать это — использовать генератор Yeoman для надстроек Office.
  2. В корневой части проекта установите Jest.
  3. Установите средство office-addin-mock.
  4. Создайте файл точно так же, как и первый файл в примере, и добавьте его в папку, содержащую другие исходные файлы проекта, часто называемые \src.
  5. Создайте вложенную папку исходного файла и присвойте ей соответствующее имя, например \tests.
  6. Создайте файл точно так же, как файл теста в примере, и добавьте его во вложенную папку.
  7. test Добавьте скрипт в файл package.json, а затем запустите тест, как описано в разделе Базовое использование.

Макетирование общих API Office

В этом примере предполагается надстройка Office для любого узла, поддерживающего общие API Office (например, Excel, PowerPoint или Word). Надстройка имеет одну из своих функций в файле с именем my-common-api-add-in-feature.js. Ниже показано содержимое файла. Функция addHelloWorldText задает в тексте "Hello World!" то, что в данный момент выбрано в документе, например диапазон в Word, ячейка в Excel или текстовое поле в PowerPoint.

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 значение, на которое ссылается метод надстройки, должно быть явно добавлено в начальный объект.
  • Так как библиотека JavaScript office не загружается в процессе узла, объект, 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!");
});

Макетирование API Outlook

Хотя, строго говоря, API Outlook являются частью общей модели API, они имеют специальную архитектуру, построенную на объекте Mailbox , поэтому мы предоставили отдельный пример для Outlook. В этом примере предполагается, что Outlook имеет одну из своих функций в файле с именем my-outlook-add-in-feature.js. Ниже показано содержимое файла. Функция 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.
  • Так как библиотека JavaScript office не загружается в процессе узла, объект, 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!");
});

Макетирование API-интерфейсов приложений Office

При тестировании функций, использующих API-интерфейсы приложений, убедитесь, что вы издеваетесь над правильным типом объекта. Возможны два варианта:

  • Макет officeExtension.ClientRequestObject. Это происходит, если проверяемая функция соответствует обоим из следующих условий:

    • Он не вызывает узел.run функция, например Excel.run.
    • Он не ссылается на любое другое прямое свойство или метод объекта Host .
  • Макет объекта Host, например Excel или Word. Сделайте это, если предыдущий параметр невозможен.

Примеры обоих типов тестов приведены в подразделах ниже.

Примечание.

Библиотека Office-Addin-Mock в настоящее время не поддерживает макетирование объектов типов коллекции, которые являются объектами в API-интерфейсах приложения, которые именуются в шаблоне *Collection, например WorksheetCollection. Мы прилагаем все усилия, чтобы добавить эту поддержку в библиотеку.

Макет объекта ClientRequestContext

В этом примере предполагается, что надстройка Excel имеет одну из своих функций в файле с именем my-excel-add-in-feature.js. Ниже показано содержимое файла. Обратите внимание, что getSelectedRangeAddress является вспомогательным методом, вызываемый внутри обратного вызова, который передается в Excel.run.

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, поэтому макетируемого объекта является родительским Excel.Workbookобъектом объекта : a ClientRequestContext .

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

Макет объекта узла

В этом примере предполагается Word надстройка, которая имеет одну из своих функций в файле с именем my-word-add-in-feature.js. Ниже показано содержимое файла.

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 находится во вложенной папке относительно расположения файла кода надстройки. Ниже показано содержимое файла. Обратите внимание, что свойство верхнего уровня — объект context, ClientRequestContext поэтому макетируемого объекта является родительским объектом этого свойства: Word object. Обратите внимание на следующие особенности этого кода:

  • OfficeMockObject Когда конструктор создает окончательный объект макета, он гарантирует, что дочерний ClientRequestContext объект имеет sync методы и load .
  • Конструктор OfficeMockObjectне добавляет функцию run в объект макета Word , поэтому ее необходимо явно добавить в начальный объект.
  • Конструктор OfficeMockObjectне добавляет все классы перечисления Word в объект макетаWord, поэтому InsertLocation.end значение, на которое ссылается метод надстройки, должно быть явно добавлено в начальный объект.
  • Так как библиотека JavaScript office не загружается в процессе узла, объект, 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.

См. также