Você pode encontrar uma lista interminável de blogs, artigos e sites que promovem os benefícios do teste unitário de seu código-fonte. É quase garantido que os desenvolvedores que programaram os compiladores para Java, C ++, C # e outras linguagens digitadas usaram testes de unidade para verificar seu trabalho.
Então, por que, apesar de sua popularidade, o teste está ausente na sintaxe desses idiomas?
A Microsoft introduziu o LINQ no C # , então por que eles não poderiam adicionar testes?
Não pretendo prever quais seriam essas mudanças de idioma, mas esclarecer por que elas estão ausentes no início.
Como exemplo: sabemos que você pode escrever um for
loop sem a sintaxe da for
instrução. Você pode usar while
ou if
/ goto
declarações. Alguém decidiu que uma for
declaração era mais eficiente e a introduziu em um idioma.
Por que os testes não seguiram a mesma evolução das linguagens de programação?
fonte
Respostas:
Como em muitas coisas, o teste de unidade é melhor suportado no nível da biblioteca, não no nível do idioma. Em particular, o C # tem inúmeras bibliotecas de teste de unidade disponíveis, além de coisas nativas do .NET Framework, como
Microsoft.VisualStudio.TestTools.UnitTesting
.Cada biblioteca de Teste de Unidade possui uma filosofia e sintaxe de teste um pouco diferente. Todas as coisas são iguais, mais opções são melhores que menos. Se o teste de unidade fosse inserido no idioma, você estaria bloqueado nas opções do designer do idioma ou estaria usando ... uma biblioteca e evitando completamente os recursos de teste de idioma.
Exemplos
Nunit - Estrutura de teste de unidade de uso geral, projetada para o idioma, que tira o máximo proveito dos recursos de linguagem do C #.
Moq - estrutura de zombaria que aproveita ao máximo as expressões lambda e as árvores de expressão, sem uma metáfora de registro / reprodução.
Existem muitas outras opções. Bibliotecas como o Microsoft Fakes podem criar zombarias "shims ..." que não exigem que você escreva suas classes usando interfaces ou métodos virtuais.
Linq não é um recurso de idioma (apesar do nome)
Linq é um recurso de biblioteca. Temos muitos recursos novos na própria linguagem C # de graça, como expressões lambda e métodos de extensão, mas a implementação real do Linq está no .NET Framework.
Há algum açúcar sintático que foi adicionado ao C # para tornar as instruções do linq mais limpas, mas esse açúcar não é necessário para usar o linq.
fonte
var
palavra-chave :)Há muitas razões. Eric Lippert afirmou muitas vezes que o motivo
feature X
não está no C # é porque não está no orçamento. Os designers de idiomas não têm uma quantidade infinita de tempo nem dinheiro para implementar as coisas, e cada novo recurso tem custos de manutenção associados. Manter o idioma o mais pequeno possível não é apenas mais fácil para os designers de idiomas - também é mais fácil para quem escreve implementações e ferramentas alternativas (por exemplo, IDEs). Além disso, quando algo é implementado em termos do idioma, e não em parte, você obtém portabilidade gratuitamente. Se o teste de unidade estiver sendo implementado como uma biblioteca, você precisará escrevê-lo apenas uma vez e ele funcionará em qualquer implementação em conformidade da linguagem.Vale a pena notar que D tem suporte no nível de sintaxe para testes de unidade . Não sei por que eles decidiram incluir isso, mas vale a pena notar que D deve ser uma "linguagem de programação de sistemas de alto nível". Os designers queriam que fosse viável para o tipo de código inseguro e de baixo nível C ++ tradicionalmente usado, e um erro no código inseguro é incrivelmente caro - comportamento indefinido. Então, suponho que fazia sentido para eles dedicar um esforço extra a qualquer coisa que o ajudasse a verificar se algum código não seguro funciona. Por exemplo, você pode impor que apenas determinados módulos confiáveis possam executar operações inseguras, como acessos não verificados à matriz ou aritmética de ponteiros.
O desenvolvimento rápido também era uma prioridade para eles, tanto que eles criaram um objetivo de design que o código D compila com rapidez suficiente para torná-lo utilizável como uma linguagem de script. Testes de unidade de cozimento diretamente no idioma, para que você possa executar seus testes, basta passar um sinalizador extra para o compilador.
No entanto, acho que uma ótima biblioteca de testes de unidade faz muito mais do que apenas encontrar alguns métodos e executá-los. Veja o QuickCheck de Haskell, por exemplo, que permite testar coisas como "para todos os x e y
f (x, y) == f (y, x)
". O QuickCheck é melhor descrito como um gerador de teste de unidade e permite que você teste as coisas em um nível mais alto do que "para esta entrada, estou esperando esta saída". QuickCheck e Linq não são tão diferentes - ambos são idiomas específicos de domínio. Portanto, em vez de usar o suporte ao teste de unidade em um idioma, por que não adicionar os recursos necessários para tornar as DSLs práticas? Você acabará não apenas com testes de unidade, mas com um idioma melhor como resultado.fonte
Porque testar, e particularmente desenvolvimento orientado a testes, é um fenômeno profundamente contra-intuitivo.
Quase todo programador começa sua carreira acreditando que é muito melhor no gerenciamento da complexidade do que realmente é. O fato de nem mesmo o maior programador conseguir escrever programas grandes e complexos sem erros graves, a menos que eles usem muitos testes de regressão é seriamente decepcionante e até vergonhoso para muitos profissionais. Daí a desinclinação predominante contra testes regulares, mesmo entre profissionais que já deveriam conhecer melhor.
Eu acho que o fato de os testes religiosos estarem lentamente se tornando mais populares e esperados se deve em grande parte ao fato de que, com a explosão da capacidade de armazenamento e do poder de computação, sistemas maiores do que nunca estão sendo construídos - e sistemas extremamente grandes são particularmente propensos ao colapso da complexidade que não pode ser gerenciado sem a rede de segurança dos testes de regressão. Como resultado, mesmo os desenvolvedores particularmente obstinados e iludidos agora admitem, relutantemente, que precisam de testes e sempre precisarão de testes (se isso soa como a confissão em uma reunião de AA, isso é bastante intencional - é necessário admitir, para muitos, a necessidade de uma rede de segurança. indivíduos).
Atualmente, a maioria dos idiomas populares data de antes dessa mudança de atitude; portanto, eles têm pouco suporte interno para testes: eles têm
assert
, mas não têm contratos. Tenho certeza de que, se a tendência persistir, os idiomas futuros terão mais suporte no idioma do que no nível da biblioteca.fonte
Muitos idiomas têm suporte para teste. As afirmações de C são testes de que o programa pode falhar. É aí que a maioria das linguagens para, mas Eiffel e, mais recentemente, o Ada 2012 têm pré-variantes (coisas que os argumentos de uma função devem passar) e pós-variantes (coisas que a saída de uma função deve passar), com a Ada oferecendo a capacidade de referenciar os argumentos iniciais no pós-variante. O Ada 2012 também oferece invariantes de tipo, portanto, sempre que um método é chamado em uma classe Ada, o invariante de tipo é verificado antes do retorno.
Esse não é o tipo de teste completo que uma boa estrutura de teste pode oferecer, mas é um tipo importante de teste que os idiomas podem suportar melhor.
fonte
Alguns defensores de linguagens funcionais fortemente tipificadas argumentariam que esses recursos de linguagem reduzem ou eliminam a necessidade de testes de unidade.
Dois, imho, um bom exemplo disso é o F # for Fun and Profit aqui e aqui
Pessoalmente, ainda acredito no valor dos testes de unidade, mas existem alguns pontos válidos. Por exemplo, se um estado ilegal é irrepresentável no código, não é apenas desnecessário escrever testes de unidade para este caso, mas também é impossível.
fonte
Eu diria que você perdeu a adição de alguns dos recursos necessários porque eles não estavam sendo destacados como nos testes de unidade .
Por exemplo, o teste de unidade em C # é direcionado principalmente pelo uso de atributos. O recurso Atributos personalizados fornece um mecanismo de extensão avançado que permite que estruturas como o NUnit iterem e competam, com coisas como testes baseados em teoria e parametrizados .
Isso me leva ao meu segundo ponto principal - não sabemos o suficiente sobre o que faz uma boa testabilidade para incorporá-lo a um idioma. O ritmo da inovação nos testes é muito mais rápido do que outras construções de linguagem, por isso precisamos ter mecanismos flexíveis em nossas línguas para deixar a liberdade de inovar.
Eu sou um usuário, mas não sou fanático por TDD - é muito útil em alguns casos, especialmente para melhorar seu design thinking. Não é necessariamente útil para sistemas legados maiores - testes de nível superior com bons dados e automação provavelmente trarão mais benefícios, juntamente com uma forte cultura de inspeção de código .
Outra leitura relevante:
fonte