Como usar o BDD para testar a unidade de um compilador?

8

Minha equipe está escrevendo um compilador para uma linguagem específica de domínio (DSL) que será integrada a um IDE. No momento, estamos focados na fase de análise do compilador. Estamos não utilizando qualquer analisador geradores existentes (como ANTLR) porque precisamos de desempenho em tempo real e altamente detalhada de erro / aviso / informação mensagem. Nós temos

  1. classes, cada uma das quais representa um nó na árvore de sintaxe concreta do idioma, bem como
  2. classes que atuam como anotações para cada nó (por exemplo, erros e informações adicionais), bem como
  3. classes internas que constroem e manipulam a árvore de sintaxe concreta (ou seja, lexer, analisador, cache de strings, visitantes de sintaxe).

Estamos tentando decidir uma estratégia geral para organizar nossos testes. Nossa empresa está promovendo o desenvolvimento orientado a comportamento (BDD) e o design orientado a domínio (DDD). Embora estejamos criando uma DSL para o domínio de nossa empresa, o domínio do compilador é uma linguagem de programação.

Ainda estamos no processo de construção do compilador e já temos alguns testes. Nosso objetivo é ter 100% de cobertura de declaração.

Atualmente, temos testes nos quais inserimos o código-fonte no construtor de árvores de sintaxe e, em seguida, executamos uma verificação em cada propriedade de cada nó da árvore de sintaxe resultante para garantir que as informações esperadas (número da linha, erros relevantes, filho) / tokens pai, largura do token, tipo de token, etc.). Agora, como cada nó é sua própria classe e certas anotações e erros anexados a um nó são classes separadas, esse teste acaba fazendo referência a muitas classes.

Atualmente, temos testes para determinadas classes, como o lexer, no qual podemos isolar a entrada (uma string) e a saída (uma lista de tokens) de outras classes (por exemplo, as classes dos nós da árvore da sintaxe). Esses testes são mais granulares.

Agora, os testes no parágrafo imediatamente acima podem ser colocados em correspondência com a classe em teste (por exemplo, lexer, cache de strings). No entanto, os testes do segundo parágrafo acima realmente testam toda a fase de análise do compilador; isto é, cada teste pode ter mais de 300 asserções para a árvore de sintaxe, dado o código-fonte de entrada. Os testes são para o comportamento da fase de análise.

Essa é uma estratégia de teste apropriada? Caso contrário, o que devemos fazer de diferente? Que estratégia de organização devemos usar para nossos testes?

cm007
fonte

Respostas:

5
  > Is this an appropriate testing strategy?

Não , porque o seu subdomínio é uma DSL (um tipo de linguagem de programação) e seu compilador faz parte de um detalhe de implementação do caso de uso que permite automatizar ações / fluxos de trabalho nesse domínio usando a DSL.

Desde que eu não sei como a sua aparência DSL como eu supor que você tem conceitos como loop, condition, statement, variableusando o exemplo

 for(int i=1;i =< 10;i++) {subtask();}

Usando uma linguagem parecida com bdd-pherkin, você poderia escrever algo como

as a automation user
i want to have a for loop with startvalue, endvalue, loopincrement
so that i can repeat subtasks several times.

given startvalue=1
and endvalue = 10
and loopinclrement = 1
when i execute for(int i=%startvalue%;i =< %endvalue %;i+=%loopinclrement%)
then the subtask should have been executet 10 times.

Isso é bastante trabalho para provar que seu compilador funciona conforme o esperado.

  > If not, what should we be doing differently? 
  > What organization strategy should we use for our tests?

Eu criaria um grande repositório de exemplos para entrada com saída correspondente.

O teste automatizado iria percorrer os exemplos e verificar se a saída do compilador corresponde à saída esperada.

Exemplo: se o seu dsl relacionado à fatura / pedido for compilado para java, uma entrada de repositório será semelhante a:

 example: loop over orderentries
 dsl-source: foreach orderitem in orders do calculateTaxes(orderitem)
 expected errormessage: none
 expected java output: for(OrderItemType orderitem : orders) 
                          {calculateTaxes(orderitem);}

 example: loop with syntax errors
 dsl-source: foreach orderitem in orders 
 expected errormessage: missing "do"-keyword in line 1
 expected java output: none

Portanto, em vez de escrever muito código para caber no bdd, basta adicionar exemplos de valores de entrada / saída codificados.

k3b
fonte