Teste de unidade em Suplementos do Office

Os testes de unidade marcam a funcionalidade do suplemento sem exigir conexões de rede ou serviço, incluindo conexões com o aplicativo do Office. Teste de unidade O código do lado do servidor e o código do lado do cliente que não chama as APIs JavaScript do Office são os mesmos nos Suplementos do Office e em qualquer aplicativo Web e, portanto, não requerem documentação especial. Mas o código do lado do cliente que chama as APIs JavaScript do Office é difícil de testar. Para resolver esses problemas, criamos uma biblioteca para simplificar a criação de objetos simulados do Office em testes de unidade: Office-Addin-Mock. A biblioteca facilita o teste das seguintes maneiras:

  • As APIs JavaScript do Office devem ser inicializadas em um controle de modo de exibição da Web no contexto de um aplicativo do Office (como Excel, PowerPoint ou Word), para que não possam ser carregadas no processo no qual os testes de unidade são executados em seu computador de desenvolvimento. Você pode importar a biblioteca Office-Addin-Mock para seus arquivos de teste, o que permite a simulação de APIs JavaScript do Office dentro do processo Node.js no qual os testes são executados.
  • As APIs específicas do aplicativo têm métodos de carregamento e sincronização que você deve chamar em uma ordem específica em relação a outras funções e entre si. Além disso, você deve chamar o load método com determinados parâmetros, dependendo das propriedades dos objetos do Office que serão lidos pelo código posteriormente na função que está sendo testada. Mas as estruturas de teste de unidade são inerentemente sem estado, portanto, elas não podem manter um registro de se load ou sync foram chamadas ou quais parâmetros foram passados para load. Os objetos fictícios que você cria com a biblioteca Office-Addin-Mock têm um estado interno que controla essas coisas. Esse estado interno permite que os objetos fictícios emulem o comportamento de erro de objetos reais do Office. Por exemplo, se a função que está sendo testada tentar ler uma propriedade que não foi passada primeiro para load, o teste retornará um erro semelhante ao que o Office retornaria.

A biblioteca não depende das APIs JavaScript do Office e você pode usá-la com qualquer estrutura de teste de unidade JavaScript, como:

Os exemplos deste artigo usam o framework Jest. Para obter exemplos que usam a estrutura Mocha, consulte a home page Office-Addin-Mock.

Pré-requisitos

Este artigo pressupõe que você esteja familiarizado com os conceitos básicos de teste de unidade e simulação, incluindo como criar e executar arquivos de teste, e que você tenha alguma experiência com uma estrutura de teste de unidade.

Dica

Se você estiver trabalhando com o Microsoft Visual Studio (VS), recomendamos que leia o artigo Teste de unidade de JavaScript e TypeScript no Visual Studio para obter algumas informações básicas sobre o teste de unidade de JavaScript no VS e, em seguida, retorne a este artigo.

Instale a ferramenta

Para instalar a biblioteca, abra um prompt de comando, navegue até a raiz do projeto do suplemento e digite o comando a seguir.

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

Uso básico

  1. Seu projeto terá um ou mais arquivos de teste. (Consulte as instruções para sua estrutura de teste e os arquivos de teste de exemplo em Exemplos abaixo.) Importe a biblioteca com a require palavra-chave ou import para qualquer arquivo de teste que tenha um teste de uma função que chama as APIs JavaScript do Office, conforme mostrado nos exemplos a seguir.

    // CommonJS
    const OfficeAddinMock = require("office-addin-mock");
    
    // ES6
    import OfficeAddinMock from "office-addin-mock";
    
  2. Importe o módulo que contém a função do suplemento que você deseja testar com a require palavra-chave ou import . Os exemplos a seguir pressupõem que o arquivo de teste está em uma subpasta da pasta com os arquivos de código do suplemento.

    // CommonJS
    const myOfficeAddinFeature = require("../my-office-add-in");
    
    // ES6
    import myOfficeAddinFeature from "../my-office-add-in";
    
  3. Crie um objeto de dados que tenha as propriedades e subpropriedades que você precisa simular para testar a função. O exemplo a seguir mostra um objeto que simula a propriedade Workbook.range.address do Excel e o método Workbook.getSelectedRange . Esse objeto não é o objeto fictício final. Pense nele como um objeto semente que OfficeMockObject usa para criar o objeto fictício final.

    const mockData = {
      workbook: {
        range: {
          address: "C2:G3",
        },
        getSelectedRange: function () {
          return this.range;
        },
      },
    };
    
  4. Passe o objeto de dados para o OfficeMockObject construtor. Observe o seguinte sobre o objeto retornado OfficeMockObject .

    • É uma simulação simplificada de um objeto OfficeExtension.ClientRequestContext .
    • O objeto fictício tem todos os membros do objeto de dados e também tem implementações simuladas dos load métodos and sync .
    • O objeto fictício imita o comportamento de erro crucial do ClientRequestContext objeto. Por exemplo, se a API do Office que você está testando tentar ler uma propriedade sem primeiro carregar a propriedade e chamar sync, o teste falhará com um erro semelhante ao que seria lançado no tempo de execução de produção: "Erro, propriedade não carregada".
    const contextMock = new OfficeAddinMock.OfficeMockObject(mockData);
    

    Observação

    A documentação de referência completa para o OfficeMockObject tipo está em Office-Addin-Mock.

  5. Na sintaxe da estrutura de teste, adicione um teste da função. Use o OfficeMockObject objeto no lugar do objeto que ele zomba, nesse caso, o ClientRequestContext objeto. O seguinte continua o exemplo em Jest. Este teste de exemplo pressupõe que a função de suplemento que está sendo testada é chamada getSelectedRangeAddress, que usa um ClientRequestContext objeto como um parâmetro e que retorna o endereço do intervalo selecionado no momento. O exemplo completo é mais adiante neste artigo.

    test("getSelectedRangeAddress should return the address of the range", async function () {
      expect(await getSelectedRangeAddress(contextMock)).toBe("C2:G3");
    });
    
  6. Execute o teste de acordo com a documentação da estrutura de teste e suas ferramentas de desenvolvimento. Normalmente, há um arquivo package.json com um script que executa a estrutura de teste. Por exemplo, se Jest for o framework, package.json conteria o seguinte:

    "scripts": {
      "test": "jest",
      -- Other scripts omitted. --  
    }
    

    Para executar o teste, insira o seguinte em um prompt de comando na raiz do projeto.

    npm test
    

Exemplos

Os exemplos nesta seção usam Jest com suas configurações padrão. Essas configurações dão suporte a módulos CommonJS. Para obter informações sobre como configurar o Jest e o Node.js para usar o TypeScript e suportar módulos ECMAScript, consulte a documentação do Jest sobre introdução e Módulos ECMAScript.

Para executar qualquer um desses exemplos, execute as etapas a seguir.

  1. Crie um projeto de Suplemento do Office para o aplicativo host do Office apropriado (por exemplo, Excel ou Word). Uma maneira de fazer isso rapidamente é usar o gerador Yeoman para Suplementos do Office.
  2. Na raiz do projeto, instale o Jest.
  3. Instale a ferramenta office-addin-mock.
  4. Crie um arquivo exatamente como o primeiro arquivo no exemplo e adicione-o à pasta que contém os outros arquivos de origem do projeto, geralmente chamada \src.
  5. Crie uma subpasta para a pasta do arquivo de origem e dê a ela um nome apropriado, como \tests.
  6. Crie um arquivo exatamente como o arquivo de teste no exemplo e adicione-o à subpasta.
  7. Adicione um test script ao arquivo package.json e execute o teste, conforme descrito em Uso básico.

Simulando as APIs Comuns do Office

Este exemplo pressupõe Suplementos do Office para qualquer host que dê suporte às APIs Comuns do Office (por exemplo, Excel, PowerPoint ou Word). O suplemento tem um de seus recursos em um arquivo chamado my-common-api-add-in-feature.js. O código a seguir mostra o conteúdo do arquivo. A addHelloWorldText função define o texto "Olá, Mundo!" para o que estiver selecionado no documento no momento; por exemplo, um intervalo no Word, uma célula no Excel ou uma caixa de texto no PowerPoint.

const myCommonAPIAddinFeature = {

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

O arquivo de teste, chamado my-common-api-add-in-feature.test.js, está em uma subpasta, relativa ao local do arquivo de código de suplemento. O código a seguir mostra o conteúdo do arquivo. A propriedade de nível superior é context, um objeto Office.Context , portanto, o objeto que está sendo simulado é o pai dessa propriedade: um objeto Office . Observe o seguinte sobre este código:

  • O OfficeMockObject construtor não adiciona todas as classes de enumeração do Office ao objeto fictício Office , portanto, você deve adicionar o CoercionType.Text valor referenciado no método de suplemento explicitamente no objeto de semente.
  • Como a biblioteca JavaScript do Office não é carregada no processo de nó, você deve declarar e inicializar o objeto referenciado Office no código do suplemento.
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!");
});

Simulando as APIs do Outlook

Embora as APIs do Outlook façam parte do modelo de API comum, elas têm uma arquitetura especial criada em torno do objeto Mailbox . Fornecemos um exemplo distinto para o Outlook. Este exemplo pressupõe um suplemento do Outlook que tem um de seus recursos em um arquivo chamado my-outlook-add-in-feature.js. O código a seguir mostra o conteúdo do arquivo. A addHelloWorldText função define o texto "Olá, Mundo!" para o que estiver selecionado atualmente na janela de redação da mensagem.

const myOutlookAddinFeature = {

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

module.exports = myOutlookAddinFeature;

O arquivo de teste, chamado my-outlook-add-in-feature.test.js, está em uma subpasta relativa ao local do arquivo de código do suplemento. O código a seguir mostra o conteúdo do arquivo. A propriedade de nível superior é context, um objeto Office.Context . O objeto que a simulação destina é o pai dessa propriedade: um objeto do Office . Observe os seguintes detalhes sobre este código.

  • A host propriedade no objeto fictício é usada internamente pela biblioteca fictícia para identificar o aplicativo do Office. É obrigatório para o Outlook. Atualmente, ele não serve para nenhum outro aplicativo do Office.
  • Como a biblioteca JavaScript do Office não é carregada no processo de nó, você deve declarar e inicializar o objeto referenciado Office no código do suplemento.
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!");
});

Simulando as APIs específicas do aplicativo do Office

Ao testar funções que usam as APIs específicas do aplicativo, simule o tipo certo de objeto. Você tem duas opções.

  • Simular um OfficeExtension.ClientRequestObject. Use essa opção quando a função que você está testando atender a ambas as condições a seguir.

    • Ele não chama um Host. run como Excel.run.
    • Ele não faz referência a nenhuma outra propriedade direta ou método de um objeto Host .
  • Simular um objeto Host, como Excel ou Word. Use essa opção quando a opção anterior não for possível.

As subseções a seguir mostram exemplos de ambos os tipos de testes.

Observação

No momento, a biblioteca Office-Addin-Mock não dá suporte à simulação de objetos do tipo coleção. Esses objetos são todos os objetos nas APIs específicas do aplicativo que seguem o padrão de nomenclatura Collection , como WorksheetCollection. Estamos trabalhando duro para adicionar esse suporte à biblioteca.

Simular um objeto ClientRequestContext

Este exemplo pressupõe um suplemento do Excel que tem um de seus recursos em um arquivo chamado my-excel-add-in-feature.js. O código a seguir mostra o conteúdo do arquivo. Observe que a getSelectedRangeAddress função é um método auxiliar chamado dentro do retorno de chamada que é passado para Excel.run.

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

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

module.exports = myExcelAddinFeature;

O arquivo de teste, chamado my-excel-add-in-feature.test.js, está em uma subpasta relativa ao local do arquivo de código do suplemento. O código a seguir mostra o conteúdo do arquivo. Observe que a propriedade de nível superior é workbook, portanto, o objeto que está sendo simulado é o pai de um Excel.Workbookobjeto : 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");
});

Simulando um objeto host

Este exemplo pressupõe um suplemento do Word que tem um de seus recursos em um arquivo chamado my-word-add-in-feature.js. O código a seguir mostra o conteúdo do arquivo.

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;

O arquivo de teste, chamado my-word-add-in-feature.test.js, está em uma subpasta relativa ao local do arquivo de código do suplemento. O código a seguir mostra o conteúdo do arquivo. Observe que a propriedade de nível superior é context, um ClientRequestContext objeto, portanto, o objeto que está sendo simulado é o pai dessa propriedade: um Word objeto. Observe os seguintes detalhes sobre este código.

  • Quando o OfficeMockObject construtor cria o objeto fictício final, ele garante que o objeto filho ClientRequestContext tenha sync métodos e load .
  • O OfficeMockObject construtor não adiciona uma run função ao objeto mock Word , portanto, você deve adicioná-la explicitamente no objeto seed.
  • O OfficeMockObject construtor não adiciona todas as classes de enumeração do Word ao objeto fictícioWord, portanto, você deve adicionar o InsertLocation.end valor referenciado no método de suplemento explicitamente no objeto seed.
  • Como a biblioteca JavaScript do Office não é carregada no processo de nó, você deve declarar e inicializar o objeto referenciado Word no código do suplemento.
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");
  });
})

Observação

A documentação de referência completa para o OfficeMockObject tipo está em Office-Addin-Mock.

Confira também