Atualmente no meu trabalho, temos um grande conjunto de testes de unidade para nosso aplicativo C ++. No entanto, não usamos uma estrutura de teste de unidade. Eles simplesmente utilizam uma macro C que basicamente envolve uma afirmação e um cout. Algo como:
VERIFY(cond) if (!(cond)) {std::cout << "unit test failed at " << __FILE__ << "," << __LINE__; asserst(false)}
Então, simplesmente criamos funções para cada um de nossos testes, como
void CheckBehaviorYWhenXHappens()
{
// a bunch of code to run the test
//
VERIFY(blah != blah2);
// more VERIFY's as needed
}
Nosso servidor de IC captura "falha no teste de unidade" e falha na compilação, enviando a mensagem por e-mail aos desenvolvedores.
E se tivermos código de instalação duplicado, simplesmente o refatoramos como qualquer outro código duplicado que teríamos em produção. Nós o envolvemos por trás das funções auxiliares, fazemos algumas classes de teste agruparem a configuração de cenários usados com freqüência.
Eu sei que existem estruturas por aí como o CppUnit e o teste de unidade de impulso. Gostaria de saber qual o valor que estes adicionam? Estou sentindo falta do que isso traz para a mesa? Existe algo útil que eu possa ganhar com eles? Estou hesitante em adicionar uma dependência, a menos que agregue valor real, especialmente porque parece que o que temos é simples e funciona bem.
fonte
Parece que você já usa uma estrutura caseira.
Qual é o valor agregado de estruturas mais populares? Eu diria que o valor que eles agregam é que, quando você tem que trocar código com pessoas de fora da sua empresa, você pode fazê-lo, pois ele se baseia na estrutura conhecida e amplamente usada .
Por outro lado, uma estrutura caseira obriga você a nunca compartilhar seu código ou a fornecer a própria estrutura, o que pode se tornar complicado com o crescimento da própria estrutura.
Se você der seu código a um colega como está, sem explicação e sem estrutura de teste de unidade, ele não poderá compilá-lo.
Uma segunda desvantagem das estruturas caseiras é a compatibilidade . Estruturas populares de teste de unidade tendem a garantir a compatibilidade com diferentes IDEs, sistemas de controle de versão etc. Por enquanto, pode não ser muito importante para você, mas o que acontecerá se um dia você precisar alterar algo no servidor de CI ou migrar para um novo IDE ou um novo VCS? Você vai reinventar a roda?
Por último, mas não menos importante, estruturas maiores fornecem mais recursos que você pode implementar em sua própria estrutura um dia.
Assert.AreEqual(expected, actual)
nem sempre é suficiente. E se você precisar:medir precisão?
teste nulo se for executado por muito tempo? Reimplementar um tempo limite pode não ser simples, mesmo em idiomas que facilitam a programação assíncrona.
testar um método que espera que uma exceção seja lançada?
tem um código mais elegante?
está bem, mas não é mais expressivo sua intenção de escrever a próxima linha?
fonte
Como outros já disseram, você já possui sua própria estrutura caseira.
A única razão que vejo para usar alguma outra estrutura de teste seria do ponto de vista do "conhecimento comum" do setor. Os novos desenvolvedores não precisariam aprender do seu jeito caseiro (embora pareça muito simples).
Além disso, outras estruturas de teste podem ter mais recursos dos quais você poderia aproveitar.
fonte
Você já possui uma estrutura, mesmo que simples.
As principais vantagens de uma estrutura maior, como as vejo, são a capacidade de ter muitos tipos diferentes de asserções (como afirmar aumentos), uma ordem lógica para os testes de unidade e a capacidade de executar apenas um subconjunto de testes de unidade em um tempo. Além disso, o padrão dos testes xUnit é bastante agradável de seguir, se você puder - por exemplo, o setUP () e tearDown (). Obviamente, isso trava você no referido quadro. Observe que algumas estruturas têm melhor integração simulada do que outras - google mock e test, por exemplo.
Quanto tempo você leva para refatorar todos os seus testes de unidade para uma nova estrutura? Dias ou algumas semanas talvez valham a pena, mas mais talvez não tanto.
fonte
Na minha opinião, vocês dois têm a vantagem e estão em "desvantagem" (sic).
A vantagem é que você tem um sistema com o qual se sente confortável e que funciona para você. Você está feliz por confirmar a validade do seu produto e provavelmente não encontraria valor comercial ao tentar alterar todos os seus testes por algo que usa uma estrutura diferente. Se você pode refatorar seu código e seus testes detectarem as alterações - ou, melhor ainda, se você puder modificar seus testes e seu código existente falhar nos testes até que seja refatorado, você terá todas as suas bases cobertas. Contudo...
Uma das vantagens de ter uma API de teste de unidade bem projetada é que há muito suporte nativo na maioria dos IDEs modernos. Isso não afetará os usuários avançados do VI e do emacs que zombam dos usuários do Visual Studio, mas para aqueles que usam um bom IDE, você pode depurar seus testes e executá-los dentro o próprio IDE. Isso é bom, no entanto, há uma vantagem ainda maior, dependendo da estrutura que você usa, e está no idioma usado para testar seu código.
Quando digo linguagem , não estou falando de uma linguagem de programação, mas de um conjunto rico de palavras envolvidas em uma sintaxe fluente que faz com que o código de teste seja lido como uma história. Em particular, me tornei um defensor do uso de estruturas de BDD . Minha API DotNet BDD favorita é StoryQ, mas existem vários outros com o mesmo objetivo básico, que é extrair um conceito de um documento de requisitos e escrevê-lo no código de maneira semelhante à maneira como ele é escrito na especificação. As APIs realmente boas, no entanto, vão ainda mais longe, interceptando todas as instruções individuais de um teste e indicando se essa instrução foi executada com êxito ou falhou. Isso é incrivelmente útil, pois você vê todo o teste executado sem retornar mais cedo, o que significa que seus esforços de depuração se tornam incrivelmente eficientes, pois você só precisa focar sua atenção nas partes do teste que falharam, sem precisar decodificar a chamada inteira seqüência. A outra coisa interessante é que a saída do teste mostra todas essas informações,
Como um exemplo do que estou falando, compare o seguinte:
Usando declarações:
Usando uma API BDD fluente: (Imagine que os bits em itálico são basicamente indicadores de método)
Agora que a sintaxe do BDD é mais longa e mais elaborada, e esses exemplos são terrivelmente inventados, no entanto, para situações de teste muito complexas nas quais muitas coisas estão mudando em um sistema como resultado de um determinado comportamento do sistema, a sintaxe do BDD oferece uma clara descrição sobre o que você está testando e como sua configuração de teste foi definida. Você pode mostrar esse código a um não programador e ele entenderá instantaneamente o que está acontecendo. Além disso, se "variable_A" falhar no teste em ambos os casos, o exemplo Asserts não será executado após a primeira afirmação até que você tenha corrigido o problema, enquanto a API BDD executará todos os métodos chamados na cadeia e indicará quais partes individuais da declaração estavam erradas.
Pessoalmente, acho que essa abordagem funciona muito melhor do que as estruturas xUnit mais tradicionais, no sentido de que a linguagem de teste é a mesma que seus clientes falarão de seus requisitos lógicos. Mesmo assim, eu consegui usar as estruturas xUnit de um estilo semelhante sem precisar inventar uma API de teste completa para apoiar meus esforços e, embora as declarações ainda efetivamente entrem em curto-circuito, elas são lidas com mais clareza. Por exemplo:
Usando Nunit :
Se você decidir explorar o uso de uma API de teste de unidade, meu conselho é experimentar um grande número de APIs diferentes por um tempo e manter a mente aberta sobre sua abordagem. Embora eu defenda pessoalmente o BDD, suas necessidades comerciais podem exigir algo diferente para as circunstâncias da sua equipe. A chave, no entanto, é evitar adivinhar o sistema existente. Você sempre pode oferecer suporte aos testes existentes com alguns testes usando outra API, se necessário, mas eu certamente não recomendaria uma enorme reescrita de teste apenas para tornar tudo igual. Como o código legado fica fora de uso, você pode facilmente substituí-lo e seus testes por um novo código, além de testar usando uma API alternativa, e isso sem a necessidade de investir em um grande esforço que não trará necessariamente nenhum valor comercial real. Quanto ao uso de uma API de teste de unidade,
fonte
O que você tem é simples e faz o trabalho. Se isso funciona para você, ótimo. Você não precisa de uma estrutura de teste de unidade convencional, e eu hesitaria em passar para o trabalho de portar uma biblioteca existente de testes de unidade para uma nova estrutura. Eu acho que o maior valor das estruturas de teste de unidade é reduzir a barreira à entrada; você apenas começa a escrever testes, porque a estrutura já está em vigor. Você já passou desse ponto e não obterá esse benefício.
O outro benefício de usar uma estrutura convencional - e é um benefício menor, a IMO - é que os novos desenvolvedores já podem estar atualizados com qualquer estrutura que você esteja usando e, portanto, exigirá menos treinamento. Na prática, com uma abordagem direta como a que você descreveu, isso não deve ser um grande problema.
Além disso, a maioria das estruturas mainstream possui certos recursos que sua estrutura pode ou não ter. Esses recursos reduzem o código do encanamento e tornam mais rápido e fácil a gravação de casos de teste:
fonte