Compartir a través de


Pruebas unitarias en complementos de Office

Las pruebas unitarias comprueban la funcionalidad del complemento sin necesidad de conexiones de red o servicio, incluidas las conexiones a la aplicación de Office. El código del lado servidor de pruebas unitarias y el código del lado cliente que no llama a las API de JavaScript de Office son los mismos en los complementos de Office que en cualquier aplicación web, por lo que no requiere documentación especial. Sin embargo, el código del lado cliente que llama a las API de JavaScript de Office es difícil de probar. Para solucionar estos problemas, hemos creado una biblioteca para simplificar la creación de objetos ficticios de Office en pruebas unitarias: Office-Addin-Mock. La biblioteca facilita las pruebas de las siguientes maneras:

  • Las API de JavaScript de Office deben inicializarse en un control de vista web en el contexto de una aplicación de Office (como Excel, PowerPoint o Word), para que no puedan cargarse en el proceso en el que se ejecutan pruebas unitarias en el equipo de desarrollo. Puede importar la biblioteca Office-Addin-Mock en los archivos de prueba, lo que permite simular las API de JavaScript de Office dentro del proceso de Node.js en el que se ejecutan las pruebas.
  • Las API específicas de la aplicación tienen métodos de carga y sincronización a los que debe llamar en un orden determinado en relación con otras funciones y entre sí. Además, debe llamar al load método con determinados parámetros en función de las propiedades de los objetos de Office que leerá el código más adelante en la función que se va a probar. Pero los marcos de pruebas unitarias son intrínsecamente sin estado, por lo que no pueden mantener un registro de si load se llamó o sync se llamó a o qué parámetros se pasaron a load. Los objetos ficticios que se crean con la biblioteca Office-Addin-Mock tienen un estado interno que realiza un seguimiento de estas cosas. Este estado interno permite que los objetos ficticios emulan el comportamiento de error de los objetos de Office reales. Por ejemplo, si la función que se está probando intenta leer una propiedad que no se pasó por primera vez a load, la prueba devuelve un error similar al que devolvería Office.

La biblioteca no depende de las API de JavaScript de Office y puede usarla con cualquier marco de pruebas unitarias de JavaScript, como:

En los ejemplos de este artículo se usa el marco Jest. Para obtener ejemplos que usan el marco mocha, consulte la página principal Office-Addin-Mock.

Requisitos previos

En este artículo se supone que está familiarizado con los conceptos básicos de pruebas unitarias y simulación, incluido cómo crear y ejecutar archivos de prueba, y que tiene cierta experiencia con un marco de pruebas unitarias.

Sugerencia

Si trabaja con Microsoft Visual Studio (VS), se recomienda leer el artículo Pruebas unitarias de JavaScript y TypeScript en Visual Studio para obtener información básica sobre las pruebas unitarias de JavaScript en VS y, a continuación, volver a este artículo.

Instalación de la herramienta

Para instalar la biblioteca, abra un símbolo del sistema, vaya a la raíz del proyecto de complemento y escriba el siguiente comando.

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

Uso básico

  1. El proyecto tendrá uno o varios archivos de prueba. (Consulte las instrucciones para el marco de pruebas y los archivos de prueba de ejemplo en Ejemplos a continuación). Importe la biblioteca con la require palabra clave o import a cualquier archivo de prueba que tenga una prueba de una función que llame a las API de JavaScript de Office, como se muestra en los ejemplos siguientes.

    // CommonJS
    const OfficeAddinMock = require("office-addin-mock");
    
    // ES6
    import OfficeAddinMock from "office-addin-mock";
    
  2. Importe el módulo que contiene la función de complemento que desea probar con la require palabra clave o import . En los ejemplos siguientes se supone que el archivo de prueba está en una subcarpeta de la carpeta con los archivos de código del complemento.

    // CommonJS
    const myOfficeAddinFeature = require("../my-office-add-in");
    
    // ES6
    import myOfficeAddinFeature from "../my-office-add-in";
    
  3. Cree un objeto de datos que tenga las propiedades y subpropiedades que necesita simular para probar la función. En el ejemplo siguiente se muestra un objeto que simula la propiedad Workbook.range.address de Excel y el método Workbook.getSelectedRange . Este objeto no es el objeto ficticio final. Piense en él como un objeto de inicialización que OfficeMockObject usa para crear el objeto ficticio final.

    const mockData = {
      workbook: {
        range: {
          address: "C2:G3",
        },
        getSelectedRange: function () {
          return this.range;
        },
      },
    };
    
  4. Pase el objeto de datos al OfficeMockObject constructor. Tenga en cuenta lo siguiente sobre el objeto devuelto OfficeMockObject .

    • Se trata de una simulación simplificada de un objeto OfficeExtension.ClientRequestContext .
    • El objeto ficticio tiene todos los miembros del objeto de datos y también tiene implementaciones ficticias de los load métodos y sync .
    • El objeto ficticio imita el comportamiento de error crucial del ClientRequestContext objeto. Por ejemplo, si la API de Office que está probando intenta leer una propiedad sin cargar primero la propiedad y llamar a sync, la prueba produce un error similar al que se produciría en tiempo de ejecución de producción: "Error, propiedad no cargada".
    const contextMock = new OfficeAddinMock.OfficeMockObject(mockData);
    

    Nota:

    La documentación de referencia completa del OfficeMockObject tipo se encuentra en Office-Addin-Mock.

  5. En la sintaxis del marco de prueba, agregue una prueba de la función. Utilice el OfficeMockObject objeto en lugar del objeto del que se simula, en este caso el ClientRequestContext objeto . A continuación, se continúa el ejemplo en Jest. En esta prueba de ejemplo se supone que la función de complemento que se está probando se denomina getSelectedRangeAddress, que toma un ClientRequestContext objeto como parámetro y que devuelve la dirección del intervalo seleccionado actualmente. El ejemplo completo es más adelante en este artículo.

    test("getSelectedRangeAddress should return the address of the range", async function () {
      expect(await getSelectedRangeAddress(contextMock)).toBe("C2:G3");
    });
    
  6. Ejecute la prueba de acuerdo con la documentación del marco de pruebas y las herramientas de desarrollo. Normalmente, hay un archivo package.json con un script que ejecuta el marco de prueba. Por ejemplo, si Jest es el marco, package.json contendrá lo siguiente:

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

    Para ejecutar la prueba, escriba lo siguiente en un símbolo del sistema en la raíz del proyecto.

    npm test
    

Ejemplos

En los ejemplos de esta sección se usa Jest con su configuración predeterminada. Esta configuración admite módulos CommonJS. Para obtener información sobre cómo configurar Jest y Node.js para usar TypeScript y admitir módulos ECMAScript, consulte la documentación de Jest sobre introducción y módulos ECMAScript.

Para ejecutar cualquiera de estos ejemplos, siga estos pasos.

  1. Cree un proyecto de complemento de Office para la aplicación host de Office adecuada (por ejemplo, Excel o Word). Una manera de hacerlo rápidamente es usar el generador de Yeoman para complementos de Office.
  2. En la raíz del proyecto, instale Jest.
  3. Instale la herramienta office-addin-mock.
  4. Cree un archivo exactamente igual que el primer archivo del ejemplo y agréguelo a la carpeta que contiene los otros archivos de origen del proyecto, a menudo denominado \src.
  5. Cree una subcarpeta en la carpeta de archivos de origen y asígnele un nombre adecuado, como \tests.
  6. Cree un archivo exactamente igual que el archivo de prueba en el ejemplo y agréguelo a la subcarpeta .
  7. Agregue un test script al archivo package.json y, a continuación, ejecute la prueba, como se describe en Uso básico.

Simulación de las API comunes de Office

En este ejemplo se supone que hay complementos de Office para cualquier host que admita las API comunes de Office (por ejemplo, Excel, PowerPoint o Word). El complemento tiene una de sus características en un archivo denominado my-common-api-add-in-feature.js. El código siguiente muestra el contenido del archivo. La addHelloWorldText función establece el texto "Hola mundo!" en lo que esté seleccionado actualmente en el documento; por ejemplo, un rango en Word, una celda en Excel o un cuadro de texto en PowerPoint.

const myCommonAPIAddinFeature = {

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

El archivo de prueba, denominado my-common-api-add-in-feature.test.js, se encuentra en una subcarpeta, en relación con la ubicación del archivo de código del complemento. El código siguiente muestra el contenido del archivo. La propiedad de nivel superior es context, un objeto Office.Context , por lo que el objeto que se está simulando es el elemento primario de esta propiedad: un objeto de Office . Tenga en cuenta lo siguiente en relación con este código:

  • El OfficeMockObject constructor no agrega todas las clases de enumeración de Office al objeto ficticio Office , por lo que debe agregar el CoercionType.Text valor al que se hace referencia en el método del complemento explícitamente en el objeto de inicialización.
  • Dado que la biblioteca de JavaScript de Office no se carga en el proceso de nodo, debe declarar e inicializar el Office objeto al que se hace referencia en el código del complemento.
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!");
});

Simulación de las API de Outlook

Aunque las API de Outlook forman parte del modelo de API común, tienen una arquitectura especial que se basa en el objeto Mailbox . Proporcionamos un ejemplo distinto para Outlook. En este ejemplo se supone que un complemento de Outlook que tiene una de sus características en un archivo denominado my-outlook-add-in-feature.js. El código siguiente muestra el contenido del archivo. La addHelloWorldText función establece el texto "Hola mundo!" en lo que esté seleccionado actualmente en la ventana de redacción del mensaje.

const myOutlookAddinFeature = {

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

module.exports = myOutlookAddinFeature;

El archivo de prueba, denominado my-outlook-add-in-feature.test.js, se encuentra en una subcarpeta relativa a la ubicación del archivo de código del complemento. El código siguiente muestra el contenido del archivo. La propiedad de nivel superior es context, un objeto Office.Context . El objeto al que el objeto ficticio tiene como destino el elemento primario de esta propiedad: un objeto de Office . Tenga en cuenta los siguientes detalles sobre este código.

  • La host biblioteca simulada usa internamente la propiedad del objeto ficticio para identificar la aplicación de Office. Es obligatorio para Outlook. Actualmente no tiene ningún propósito para ninguna otra aplicación de Office.
  • Dado que la biblioteca de JavaScript de Office no se carga en el proceso de nodo, debe declarar e inicializar el Office objeto al que se hace referencia en el código del complemento.
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!");
});

Simulación de las API específicas de la aplicación de Office

Cuando se prueban funciones que usan las API específicas de la aplicación, se simula el tipo correcto de objeto. Tiene dos opciones.

  • Simular un Objeto OfficeExtension.ClientRequestObject. Use esta opción cuando la función que está probando cumpla las dos condiciones siguientes.

    • No llama a un host. run como Excel.run.
    • No hace referencia a ninguna otra propiedad o método directo de un objeto Host .
  • Simular un objeto Host, como Excel o Word. Use esta opción cuando no sea posible la opción anterior.

En las subsecciones siguientes se muestran ejemplos de ambos tipos de pruebas.

Nota:

La biblioteca Office-Addin-Mock no admite actualmente objetos de tipo de colección ficticios. Estos objetos son todos los objetos de las API específicas de la aplicación que siguen el patrón de nomenclatura colección , como WorksheetCollection. Estamos trabajando duro para agregar esta compatibilidad a la biblioteca.

Simulación de un objeto ClientRequestContext

En este ejemplo se supone que un complemento de Excel que tiene una de sus características en un archivo denominado my-excel-add-in-feature.js. El código siguiente muestra el contenido del archivo. Tenga en cuenta que la getSelectedRangeAddress función es un método auxiliar llamado dentro de la devolución de llamada que se pasa a Excel.run.

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

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

module.exports = myExcelAddinFeature;

El archivo de prueba, denominado my-excel-add-in-feature.test.js, se encuentra en una subcarpeta relativa a la ubicación del archivo de código del complemento. El código siguiente muestra el contenido del archivo. Tenga en cuenta que la propiedad de nivel superior es workbook, por lo que el objeto que se está simulando es el elemento primario de : Excel.Workbookun ClientRequestContext objeto .

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

Simulación de un objeto host

En este ejemplo se supone que un complemento de Word que tiene una de sus características en un archivo denominado my-word-add-in-feature.js. El código siguiente muestra el contenido del archivo.

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;

El archivo de prueba, denominado my-word-add-in-feature.test.js, se encuentra en una subcarpeta relativa a la ubicación del archivo de código del complemento. El código siguiente muestra el contenido del archivo. Tenga en cuenta que la propiedad de nivel superior es context, un ClientRequestContext objeto , por lo que el objeto que se está simulando es el elemento primario de esta propiedad: un Word objeto . Tenga en cuenta los siguientes detalles sobre este código.

  • Cuando el OfficeMockObject constructor crea el objeto ficticio final, se asegura de que el objeto secundario ClientRequestContext tiene sync métodos y load .
  • El OfficeMockObject constructor no agrega una run función al objeto ficticio Word , por lo que debe agregarla explícitamente en el objeto de inicialización.
  • El OfficeMockObject constructor no agrega todas las clases de enumeración de Word al objeto ficticioWord, por lo que debe agregar el InsertLocation.end valor al que se hace referencia en el método del complemento explícitamente en el objeto de inicialización.
  • Dado que la biblioteca de JavaScript de Office no se carga en el proceso de nodo, debe declarar e inicializar el Word objeto al que se hace referencia en el código del complemento.
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");
  });
})

Nota:

La documentación de referencia completa del OfficeMockObject tipo se encuentra en Office-Addin-Mock.

Vea también