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 ensharedTestTeardown
)this.eventsFireStub
this.sharedCleanup
(se usa conaddMessageToCleanup
yaddBlockTypeToCleanup
) (NOTA: No es necesario usaraddBlockTypeToCleanup
si definiste el bloque condefineBlocksWithJsonArray
).
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
yaddBlockTypeToCleanup
. - 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 asharedTestTeardown.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ásthis.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áticamentesharedTestTeardown
- 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 aworkspaceTeardown.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 aworkspaceTeardown.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 llamandoworkspaceTeardown.call(this, this.workspace)
nuevamente en el desmontaje de este paquete interno.
- Si defines
Estructura de pruebas
Las pruebas de unidades suelen seguir una estructura establecida, que se puede resumir como organizar, actuar y afirmar.
- Organizar: Configura el estado del mundo y las condiciones necesarias para el comportamiento que se está probando.
- Act: Llama al código que se está probando para activar el comportamiento que se está probando.
- 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
yteardown
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 intercambiasactual
yexpected
, 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.
- 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). - 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.
- 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ó. - 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ó. - 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ó. - 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ó. - 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
- Carga
tests/generators/index.html
en un navegador. - 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.
- Realiza cualquier cambio o adición a los bloques.
- Haz clic en "XML".
- Copia el XML generado en el archivo correspondiente en
tests/generators/
.