Pruebas de unidades

Después de cambiar o agregar código, debes ejecutar pruebas de unidades existentes y considerar escribir más. Todas las pruebas se ejecutan en las versiones sin comprimir del código.

Existen dos conjuntos de pruebas de unidades: pruebas de JS y pruebas del generador de bloques.

Pruebas de JS

Las pruebas de JS confirman el funcionamiento de las funciones internas de JavaScript en el núcleo de Blockly. Usamos Mocha para ejecutar pruebas de unidades, Sinon para crear stubs de dependencias y Chai para hacer aserciones sobre el código.

Ejecución de pruebas

En blockly y blockly-samples, npm run test ejecutará las pruebas de unidades. En Blockly, también se ejecutarán otras pruebas, como linting y compilación. Puedes También abre tests/mocha/index.html en un navegador para ejecutar todo el contenido de Moca de forma interactiva. y pruebas.

Pruebas de escritura

Usamos la interfaz de TDD de Mocha para ejecutar pruebas. Las pruebas se organizan en conjuntos, que pueden contener subconjuntos o pruebas adicionales. Por lo general, cada componente de Blockly (como toolbox o workspace) tiene su propio archivo de prueba que contiene uno o más suites. Cada suite puede tener un método setup y teardown al que se llamará antes y después, respectivamente, de cada prueba de esa suite.

Asistentes de prueba

Tenemos una serie de funciones auxiliares específicas de Blockly que pueden ser útiles cuando escribir pruebas. Puedes encontrarlas en core y en blockly-samples.

Las funciones auxiliares incluyen sharedTestSetup y sharedTestTeardown, a las que se debe llamar antes y después de las pruebas (consulta la sección Requisitos).

sharedTestSetup:
  • Configura cronómetros falsos de sinon (en algunas pruebas, deberás usar this.clock.runAll).
  • Genera un stub de Blockly.Events.fire para que se active de inmediato (configurable).
  • Configura la limpieza automática de los blockTypes definidos. defineBlocksWithJsonArray
  • Declara algunas propiedades en el contexto this que deben accesible:
    • this.clock (pero no debe restablecerse, ya que causará problemas en sharedTestTeardown)
    • this.eventsFireStub
    • this.sharedCleanup (se usa con addMessageToCleanup y addBlockTypeToCleanup) (NOTA: No es necesario usar addBlockTypeToCleanup si definiste el bloque con defineBlocksWithJsonArray).

La función tiene un parámetro options opcional para configurar la configuración. Actualmente, solo se usa para determinar si se debe crear un stub de Blockly.Events.fire para que se active de inmediato (se creará un stub de forma predeterminada).

sharedTestTeardown:
  • Elimina el lugar de trabajo this.workspace (según dónde se definió, consulta la sección Requisitos de prueba para obtener más información).
  • Restablece todos los stubs.
  • Limpia todos los tipos de bloques agregados a través de defineBlocksWithJsonArray y addBlockTypeToCleanup.
  • Limpia todos los mensajes agregados a través de addMessageToCleanup.

Requisitos de prueba

  • Cada prueba debe llamar a sharedTestSetup.call(this); como la primera línea en la configuración del paquete más externo y a sharedTestTeardown.call(this); como la última línea en el desmontaje del paquete más externo de un archivo.
  • Si necesitas un espacio de trabajo con una caja de herramientas genérica, puedes usar uno de los cajas de herramientas predefinidas en el index.html de prueba. Consulta el siguiente ejemplo.
  • Debes desechar correctamente this.workspace. En la mayoría de las pruebas, definirás this.workspace en el paquete más externo y lo usarás para todas las pruebas posteriores, pero en algunos casos, es posible que lo definas o redefinas en un paquete interno (por ejemplo, una de tus pruebas requiere un espacio de trabajo con opciones diferentes a las que configuraste originalmente). Se debe desechar al final de la prueba.
    • Si defines this.workspace en el paquete más externo y nunca vuelves a definirlo no es necesario que realices ninguna otra acción. El sistema lo eliminará automáticamente sharedTestTeardown
    • Si defines this.workspace por primera vez en un paquete interno (es decir, no lo definiste en el paquete más externo), debes eliminarlo de forma manual llamando a workspaceTeardown.call(this, this.workspace) en el desmontaje de ese paquete.
    • Si defines this.workpace en el paquete más externo, pero luego lo redefines en un paquete de prueba interno, primero debes llamar a workspaceTeardown.call(this, this.workspace) antes de redefinirlo para derribar el espacio de trabajo original definido en el paquete de nivel superior. Tú también debes descartar manualmente el valor nuevo llamando workspaceTeardown.call(this, this.workspace) nuevamente en el desmontaje de este paquete interno.

Estructura de pruebas

Las pruebas de unidades suelen seguir una estructura establecida, que se puede resumir como organizar, actuar y afirmar.

  1. Organizar: Configura el estado del mundo y las condiciones necesarias para el comportamiento que se está probando.
  2. Act: Llama al código que se está probando para activar el comportamiento que se está probando.
  3. Assert: Realiza aserciones sobre el valor que se muestra o las interacciones con él. los objetos ficticios para verificar la precisión.

En una prueba simple, es posible que no haya ningún comportamiento que organizar, y el acto y las etapas de aserción se pueden combinar integrando la llamada al código bajo prueba en el . Para casos más complejos, las pruebas serán más legibles si te atascas a estas 3 etapas.

Este es un archivo de prueba de ejemplo (simplificado a partir del elemento real).

suite('Flyout', function() {
  setup(function() {
    sharedTestSetup.call(this);
    this.toolboxXml = document.getElementById('toolbox-simple');
    this.workspace = Blockly.inject('blocklyDiv',
        {
          toolbox: this.toolboxXml
        });
  });

  teardown(function() {
    sharedTestTeardown.call(this);
  });

  suite('simple flyout', function() {
    setup(function() {
      this.flyout = this.workspace.getFlyout();
    });
    test('y is always 0', function() {
      // Act and assert stages combined for simple test case
      chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout is 0');
    });
    test('x is right of workspace if flyout at right', function() {
      // Arrange
      sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
        viewWidth: 100,
      });
      this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
      this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;

      // Act
      var x = this.flyout.getX();

      // Assert
      chai.assert.equal(x, 100, 'x is right of workspace');
    });
  });
});

Aspectos que debes tener en cuenta en este ejemplo:

  • Una suite puede incluir otras suites que tengan setup y teardown adicionales .
  • Cada suite y prueba tiene un nombre descriptivo.
  • Las aserciones de Chai se usan para hacer aserciones sobre el código.
    • Puedes proporcionar un argumento de cadena opcional que se muestre si el la prueba falla. Esto facilita la depuración de pruebas fallidas.
    • El orden de los parámetros es chai.assert.equal(actualValue, expectedValue, optionalMessage). Si intercambias actual y expected, los mensajes de error no tendrán sentido.
  • Sinon se usa para los métodos de stub cuando no deseas llamar al código real. En este ejemplo, no queremos llamar a la función de métricas real porque no es relevante para esta prueba. Solo nos interesa la forma en que usan los resultados el método que se está probando. Sinon crea un stub de la función getMetrics para mostrar una respuesta predeterminada que podemos verificar fácilmente en nuestras aserciones de prueba.
  • Los métodos setup de cada paquete solo deben contener una configuración genérica que se aplica a todas las pruebas. Si una prueba de un comportamiento en particular se basa en una condición determinada, esa condición debe indicarse claramente en la prueba relevante.

Pruebas de depuración

  • Puedes abrir las pruebas en un navegador y usar las herramientas para desarrolladores para establecer puntos de interrupción y analizar si las pruebas fallan de forma inesperada (o si aprueban de forma inesperada).
  • Establece .only() o .skip() en una prueba o un conjunto para ejecutar solo ese conjunto de pruebas o omitir una prueba. Por ejemplo:

    suite.only('Workspace', function () {
      suite('updateToolbox', function () {
        test('test name', function () {
          // ...
        });
        test.skip('test I don’t care about', function () {
          // ...
        });
      });
    });
    

    Recuerda quitarlos antes de confirmar tu código.

Pruebas de generadores de bloques

Cada bloque tiene sus propias pruebas de unidad. Estas pruebas verifican que los bloqueos generen código que las funciones según lo previsto.

  1. Carga tests/generators/index.html en Firefox o Safari. Ten en cuenta que Chrome y Opera tienen restricciones de seguridad que impiden cargar las pruebas desde el sistema local "file://" (problemas 41024 y 47416).
  2. Elige la parte relevante del sistema para probar en el menú desplegable. haz clic en "Cargar". Los bloques deberían aparecer en el espacio de trabajo.
  3. Haz clic en "JavaScript".
    Copia y ejecuta el código generado en una consola de JavaScript. Si el resultado finaliza con "OK", significa que la prueba pasó.
  4. Haz clic en “Python”.
    Copia y ejecuta el código generado en un intérprete de Python. Si el resultado termina con "OK", la prueba se aprobó.
  5. Haz clic en “PHP”.
    Copia y ejecuta el código generado en un intérprete de PHP. Si el resultado termina con "OK", la prueba se aprobó.
  6. Haz clic en "Lua".
    Copia y ejecuta el código generado en un intérprete de Lua. Si el resultado termina con "OK", significa que la prueba finalizó.
  7. Haz clic en "Dart".
    Copia y ejecuta el código generado en un intérprete de Dart. Si el resultado termina con "OK", la prueba se aprobó.

Cómo editar pruebas del generador de bloqueos

  1. Carga tests/generators/index.html en un navegador.
  2. Elige la parte relevante del sistema en el menú desplegable y haz clic en "Cargar". Los bloques deberían aparecer en el espacio de trabajo.
  3. Realiza cualquier cambio o adición a los bloques.
  4. Haz clic en "XML".
  5. Copia el XML generado en el archivo correspondiente en tests/generators/.