Depois de alterar ou adicionar o código, execute testes de unidade existentes e considere programar mais. Todos os testes são executados nas versões não compactadas do código.
Há dois conjuntos de testes de unidade: testes JS e testes do gerador de blocos.
Testes JS
Os testes JS confirmam a operação das funções JavaScript internas no núcleo do Blockly. Usamos Mocha para executar testes de unidade, Sinon para criar dependências de stub e Chai para fazer declarações sobre o código.
Como executar testes
Em amostras em blocos e em blocos, o npm run test
vai executar os testes de unidade. Em
bloco, ele também vai executar outros testes, como inspeção e compilação. Também é possível
abrir tests/mocha/index.html
em um navegador para executar de forma interativa todos os testes
mocha.
Como programar testes
Usamos a interface do Mocha TDD para executar testes. Os testes são organizados em pacotes,
que podem conter subpacotes e/ou testes adicionais. Geralmente, cada
componente do Blockly (como toolbox
ou workspace
) tem o próprio arquivo de teste
que contém um ou mais pacotes. Cada pacote pode ter um método setup
e teardown
que será chamado antes e depois de cada teste nesse pacote, respectivamente.
Auxiliares de testes
Temos várias funções auxiliares específicas do Blockly que podem ser úteis ao programar testes. Eles podem ser encontrados nas amostras core e blockly-samples.
As funções auxiliares incluem sharedTestSetup
e sharedTestTeardown
, que
são obrigatórias para serem chamadas antes e depois dos testes (consulte a seção
"Requisitos").
sharedTestSetup
:
- Configura timers falsos sinon (em alguns testes, você precisará usar
this.clock.runAll
). - Stubs Blockly.Events.fire para disparar imediatamente (configurável).
- Configura a limpeza automática de blockTypes definidos usando
defineBlocksWithJsonArray
. - Declara algumas propriedades no contexto
this
que precisam ser acessíveis:this.clock
(mas não pode ser restaurado, porque isso vai causar problemas emsharedTestTeardown
)this.eventsFireStub
this.sharedCleanup
(para ser usado comaddMessageToCleanup
eaddBlockTypeToCleanup
). OBSERVAÇÃO: você não precisa usaraddBlockTypeToCleanup
se definiu o bloco usandodefineBlocksWithJsonArray
.
A função tem um parâmetro options
opcional para configurar. Atualmente,
ele só é usado para determinar se o stub do Blockly.Events.fire
precisa ser disparado
imediatamente (por padrão, ele é stub).
sharedTestTeardown
:
- Descarta do espaço de trabalho
this.workspace
(dependendo do local em que foi definido, consulte a seção "Requisitos de teste" para mais informações). - Restaura todos os stubs.
- Limpa todos os tipos de bloco adicionados usando
defineBlocksWithJsonArray
eaddBlockTypeToCleanup
. - Limpa todas as mensagens adicionadas usando
addMessageToCleanup
.
Requisitos de teste
- Cada teste precisa chamar
sharedTestSetup.call(this);
como a primeira linha de configuração do pacote externo esharedTestTeardown.call(this);
como a última linha da desmontagem do pacote externo de um arquivo. - Se você precisar de um espaço de trabalho com uma caixa de ferramentas genérica, use uma das
caixas de ferramentas predefinidas
no teste
index.html
. Veja abaixo um exemplo. - Descarte corretamente
this.workspace
. Na maioria dos testes, você definiráthis.workspace
no pacote mais externo e o usará para todos os testes subsequentes, mas, em alguns casos, é possível defini-lo ou redefini-lo em um pacote interno. Por exemplo, um dos seus testes requer um espaço de trabalho com opções diferentes daquelas configuradas originalmente. Descarte esses itens ao final do teste.- Se você definir
this.workspace
no conjunto externo e nunca o redefinir, nenhuma outra ação será necessária. Ele será descartado automaticamente porsharedTestTeardown
. - Se você definir
this.workspace
pela primeira vez em um pacote interno, ou seja, não tiver definido no conjunto mais externo, será necessário descartar manualmente o conjunto chamandoworkspaceTeardown.call(this, this.workspace)
na desmontagem desse conjunto. - Se você definir
this.workpace
no pacote mais externo, mas depois redefinir em um pacote de testes interno, chameworkspaceTeardown.call(this, this.workspace)
antes de redefini-lo para eliminar o espaço de trabalho original definido no pacote de nível superior. Você também precisa descartar manualmente o novo valor chamandoworkspaceTeardown.call(this, this.workspace)
novamente na desmontagem desse pacote interno.
- Se você definir
Estrutura do teste
Os testes de unidade geralmente seguem uma estrutura definida, que pode ser resumida como arrange, Act, assert.
- Organizar: define o estado do mundo e todas as condições necessárias para o comportamento em teste.
- Agir: chame o código em teste para acionar o comportamento que está sendo testado.
- Assert: faça declarações sobre o valor de retorno ou interações com objetos simulados para verificar a exatidão.
Em um teste simples, pode não haver nenhum comportamento a ser organizado. Além disso, os estágios de "Agir" e "assert" podem ser combinados com a inserção da chamada ao código que está sendo testado na declaração. Em casos mais complexos, os testes ficarão mais legíveis se você seguir esses três estágios.
Veja um exemplo de arquivo de teste (simplificado do modo 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');
});
});
});
Observações sobre este exemplo:
- Um pacote pode conter outros pacotes que têm outros métodos
setup
eteardown
. - Cada pacote e teste possui um nome descritivo.
- As declarações de Chai são usadas para fazer declarações sobre o código.
- Você pode fornecer um argumento de string opcional que será exibido se o teste falhar. Isso facilita a depuração de testes corrompidos.
- A ordem dos parâmetros é
chai.assert.equal(actualValue, expectedValue, optionalMessage)
. Se você trocaractual
eexpected
, as mensagens de erro não farão sentido.
- Sinon é usado para criar stubs de métodos quando você não quer chamar o código real. Neste exemplo, não queremos chamar a função de métricas real porque ela não é relevante para o teste. Só nos preocupamos em como os resultados são usados pelo
método em teste. O Sinon cria stubs da função
getMetrics
para retornar uma resposta automática que pode ser facilmente verificada nas declarações de teste. - Os métodos
setup
de cada pacote precisam conter apenas uma configuração genérica que se aplica a todos os testes. Se o teste de um comportamento específico depender de uma determinada condição, ela precisará ser declarada claramente no teste relevante.
Testes de depuração
- Abra os testes em um navegador e use as ferramentas para desenvolvedores para definir pontos de interrupção e investigar se os testes estão falhando inesperadamente (ou passando de forma inesperada).
Defina
.only()
ou.skip()
em um teste ou pacote para executar apenas esse conjunto ou pule um teste. Exemplo:suite.only('Workspace', function () { suite('updateToolbox', function () { test('test name', function () { // ... }); test.skip('test I don’t care about', function () { // ... }); }); });
Lembre-se de removê-los antes de confirmar seu código.
Testes de gerador de blocos
Cada bloco tem seus próprios testes de unidade. Esses testes verificam se os blocos geram código do que funções conforme o esperado.
- Carregue
tests/generators/index.html
no Firefox ou Safari. O Chrome e o Opera têm restrições de segurança que impedem o carregamento dos testes do sistema "file://" local (problemas 41024 e 47416). - Escolha a parte relevante do sistema a ser testada no menu suspenso e clique em "Carregar". Os blocos devem aparecer no espaço de trabalho.
- Clique em "JavaScript".
Copie e execute o código gerado em um Console JavaScript. Se a saída terminar com "OK", o teste terá sido aprovado. - Clique em "Python".
Copie e execute o código gerado em um interpretador do Python. Se a saída terminar com "OK", o teste foi aprovado. - Clique em "PHP".
Copie e execute o código gerado em um intérprete de PHP. Se a saída terminar com "OK", o teste foi aprovado. - Clique em "Lua".
Copie e execute o código gerado em um intérprete do Lua. Se a saída terminar com "OK", o teste foi aprovado. - Clique em "Dart".
Copie e execute o código gerado em um intérprete do Dart. Se a saída terminar com "OK", o teste foi aprovado.
Como editar testes do gerador de blocos
- Carregue
tests/generators/index.html
em um navegador. - Escolha a parte relevante do sistema no menu suspenso e clique em "Load". Os blocos devem aparecer no espaço de trabalho.
- Faça alterações ou adições aos blocos.
- Clique em "XML".
- Copie o XML gerado no arquivo apropriado em
tests/generators/
.