Pergunta

Este é um difícil e pergunta aberta eu sei, mas eu pensei que eu iria jogá-lo no chão e ver se alguém tinha alguma sugestões interessantes.

Eu tenho desenvolvido um código de gerador que leva o nosso python interface para o nosso código C++ (gerado através GOLE) e gera o código necessário para expor isso como WebServices.Quando eu desenvolvi esse código que eu fiz usando TDD, mas encontrei meus testes a ser frágil como o inferno.Porque cada teste, essencialmente, queria verificar que, para um dado bit de entrada de código (o que acontece para ser um de cabeçalho C++) gostaria de obter um determinado bit de saída de código que eu escrevi um pequeno motor que lê as definições de teste a partir de XML arquivos de entrada e gera casos de teste a partir dessas expectativas.

O problema é que eu querer ir para modificar o código.Isso e o fato de que os testes de unidade em si são um:complexo, e b:frágil.

Então, eu estou tentando pensar em abordagens alternativas para este problema, e parece-me que eu sou, talvez, abordando-o de forma errada.Talvez eu preciso focar mais no resultado, ou seja:o código que gera, na verdade, executar e fazer o que eu quero que ele, ao invés do que, o código de olhar a maneira que eu quiser.

Alguém tem alguma experiência de algo semelhante a este que teria o cuidado de compartilhar?

Foi útil?

Solução

Eu comecei a escrever um resumo de minha experiência com o meu próprio gerador de código e, em seguida, voltou-se e re-ler sua pergunta e descobri que você já tinha tocado com o mesmo problemas de si mesmo, o foco sobre os resultados da execução, em vez de o código de layout/visual.

O problema é que isto é difícil de teste, o código gerado pode não ser adequado para realmente executar no ambiente de teste de unidade do sistema, e como você codificar os resultados esperados?

Eu achei que você precisa para quebrar o gerador de código em pedaços menores e teste de unidade, aqueles.O teste de unidade de um completo gerador de código é mais parecido com o teste de integração de testes de unidade se você me perguntar.

Outras dicas

Lembre-se que "teste de unidade" é apenas um tipo de teste.Você deve ser capaz de teste de unidade o interno as peças do seu gerador de código.O que você está realmente procurando aqui é o sistema de teste de nível (de um.k.um.teste de regressão).Não é apenas semântica...existem diferentes modos de pensar, abordagens, expectativas, etc.É certamente mais trabalho, mas provavelmente você precisará morder a bala e configurar um fim-a-fim de o teste de regressão suite:fixo arquivos C++ - > GOLE interfaces -> módulos python -> conhecido saída.Você realmente quer para verificar o conhecido de entrada (fixo código C++) contra o resultado esperado (o que vem de fora da grande final programa Python).Verificar o código do gerador de resultados diretamente como seria diffing objeto de arquivos...

Sim, os resultados são a ÚNICA coisa que importa.A tarefa real é a escrita de uma estrutura que permite que o código gerado para executar de forma independente...gastar o seu tempo lá.

Se você estiver executando em *nux você pode considerar despejar o unittest quadro em favor de um script bash ou makefile.no windows, você pode considerar a construção de um shell app/função que executa o gerador e, em seguida, usa o código (como outro processo) e unittest que.

Uma terceira opção seria gerar o código e, em seguida, criar um aplicativo que inclui nada, mas um unittest.Novamente, você precisará de um shell script ou outros enfeites para executar este procedimento para cada entrada.Como codificar o comportamento esperado, ocorre-me que isso poderia ser feito da mesma forma como você faria para o código C++, usando apenas a interface gerada em vez de C++ um.

Só queria salientar que você ainda pode alcançar o fine-grained o teste, apesar de verificar os resultados:você pode testar individuais blocos de código aninhando-los dentro de alguns instalação e o código de verificação:

int x = 0;
GENERATED_CODE
assert(x == 100);

Desde que você tenha o código gerado montado a partir de pedaços menores, e as partes não são alterados com freqüência, pode ter mais condições de teste e um pouco melhor, e espero que evitar todos os seus testes de quebra de quando você alterar os detalhes de um bloco.

O teste de unidade é apenas que o teste de uma unidade específica.Então, se você estiver escrevendo uma especificação para a classe A, ele é ideal se a classe não tem o real concreto versões do classe B e C.

Ok, eu notei depois, a tag para esta questão inclui C++ / Python, mas os princípios são os mesmos:

    public class A : InterfaceA 
    {   
      InterfaceB b;

      InterfaceC c;

      public A(InterfaceB b, InterfaceC c)   {
          this._b = b;
          this._c = c;   }

      public string SomeOperation(string input)   
      {
          return this._b.SomeOtherOperation(input) 
               + this._c.EvenAnotherOperation(input); 
      } 
    }

Porque o Sistema acima Um injeta interfaces para sistemas B e C, pode-unidade de teste de sistema apenas Um, sem ter a real funcionalidade a ser executada por qualquer outro sistema.Este é o teste de unidade.

Aqui é uma inteligente forma de se aproximar de um Sistema, desde a criação até a conclusão, com um diferente Quando especificação para cada peça de comportamento:

public class When_system_A_has_some_operation_called_with_valid_input : SystemASpecification
{
    private string _actualString;

    private string _expectedString;

    private string _input;

    private string _returnB;

    private string _returnC;

    [It]
    public void Should_return_the_expected_string()
    {
        _actualString.Should().Be.EqualTo(this._expectedString);
    }

    public override void GivenThat()
    {
        var randomGenerator = new RandomGenerator();
        this._input = randomGenerator.Generate<string>();
        this._returnB = randomGenerator.Generate<string>();
        this._returnC = randomGenerator.Generate<string>();

        Dep<InterfaceB>().Stub(b => b.SomeOtherOperation(_input))
                         .Return(this._returnB);
        Dep<InterfaceC>().Stub(c => c.EvenAnotherOperation(_input))
                         .Return(this._returnC);

        this._expectedString = this._returnB + this._returnC;
    }

    public override void WhenIRun()
    {
        this._actualString = Sut.SomeOperation(this._input);
    }
}

Portanto, em conclusão, uma única unidade / especificação pode ter vários comportamentos, e a especificação cresce à medida que você desenvolver a unidade / sistema;e se o sistema sob teste depende de outros sistemas concretos dentro dela, assista fora.

Minha recomendação seria a de descobrir um conjunto conhecido de entrada-saída de resultados, tais como alguns casos mais simples que você já tem no local, e teste de unidade o código que é produzido.É inteiramente possível que a medida que você alterar o gerador que a exata seqüência de caracteres que é produzido pode ser ligeiramente diferente...mas o que realmente importa é se ela é interpretada da mesma maneira.Assim, se os resultados do teste como você poderia testar esse código se fosse seu recurso, você vai descobrir se é bem sucedido da maneira que você quer.

Basicamente, o que você realmente quer saber é se o seu gerador vai produzir o que você espera sem fisicamente teste todas as combinações possíveis (também:impossível).Garantindo que o gerador é consistente da maneira que você espera, você pode sentir-se melhor que o gerador vai ter sucesso em cada vez mais situações complexas.

Desta forma, você também pode construir um conjunto de testes de regressão (testes de unidade que precisa para se manter a funcionar correctamente).Isso ajudará você a se certificar de que as alterações para o seu gerador não quebrar outras formas de código.Quando você encontrar um bug que seus testes de unidade não pegar, você pode querer incluí-lo para evitar semelhante a ruptura.

Eu acho que você precisa testar o que você está gerando mais do que a forma como o gere.

No meu caso, o programa gera muitos tipos de código (C#, HTML, ESCS, JS, etc.) que compilar em um aplicativo web.A melhor maneira que eu encontrei para reduzir erros de regressão geral é testar a aplicação web em si, não pelo teste do gerador.

Não me interpretem mal, há ainda testes de unidade a verificação de alguns de que o gerador de código, mas o nosso maior estrondo para o nosso investimento tem sido testes de INTERFACE do usuário gerado aplicativo em si.

Desde que nós somos a geração que nós também gerar uma boa abstração em JS podemos usar programaticamente o teste o aplicativo.Seguimos algumas idéias descritas aqui: http://code.tutsplus.com/articles/maintainable-automated-ui-tests--net-35089

A grande parte é que realmente nos testes de seu sistema end-to-end, desde a geração de código para o que você realmente está gerando.Uma vez que um teste falhar, a sua fácil rastreá-lo de volta para onde o gerador quebrou.

É muito doce.

Boa sorte!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top