Acabei de me formar em CS e atualmente trabalho como desenvolvedor .NET Júnior (C #, ASP.NET e formulários da web). Quando eu ainda estava na universidade, o assunto dos testes de unidade era coberto, mas eu nunca vi os benefícios disso. Entendo o que ele deve fazer, a saber, determinar se um bloco de código é ou não adequado para uso. No entanto, eu nunca tive que escrever um teste de unidade antes, nem senti a necessidade.
Como eu já mencionei, geralmente estou desenvolvendo com formulários da Web ASP.NET, e recentemente estive pensando em escrever alguns testes de unidade. Mas eu tenho algumas perguntas sobre isso.
Eu li que o teste de unidade geralmente acontece através da escrita de "zombarias". Embora eu entenda esse conceito, não consigo descobrir como devo escrever zombarias para sites completamente dinâmicos e onde quase tudo depende dos dados provenientes de um banco de dados. Por exemplo: eu uso muitos repetidores que têm eventos ItemDataBound etc. (novamente dependendo dos dados "desconhecidos").
Então, pergunta número 1: escrever testes de unidade para formulários da Web do ASP.NET é algo que é feito com freqüência e se é: como resolver o problema do "ambiente dinâmico"?
Quando estou desenvolvendo, passo por muitas tentativas e erros. Isso não significa que não sei o que estou fazendo, mas quero dizer que geralmente escrevo algum código, bato Ctrl F5e vejo o que acontece. Embora essa abordagem faça o trabalho a maior parte do tempo, às vezes sinto que estou sendo um pouco sem noção (por causa da minha pouca experiência). Às vezes, também perco muito tempo assim.
Então, pergunta número 2: Vocês me aconselham a começar a escrever testes de unidade? Acho que isso pode me ajudar na implementação real, mas, novamente, sinto que isso pode me atrapalhar.
fonte
Respostas:
Na minha opinião: sim, são e sim, você deveria.
Eles dão a você confiança nas alterações que você faz (todo o resto ainda está funcionando). Essa confiança é o que você precisa para moldar o código; caso contrário, você pode ter medo de mudar as coisas.
Eles tornam seu código melhor; os erros mais simples são detectados cedo nos testes de unidade. Capturar bugs cedo e corrigi-los é sempre mais barato do que corrigi-los mais tarde, por exemplo, quando o aplicativo está em produção.
Eles servem como documentação para outros desenvolvedores sobre como seu código funciona e como usá-lo.
O primeiro problema que você enfrenta é que o ASP.NET, por si só, não ajuda a escrever testes de unidade - na verdade, funciona contra você. Se você tiver alguma escolha, comece a usar o ASP.NET MVC , que foi criado com o teste de unidade em mente. Se você não pode usar o ASP.NET MVC, deve usar o padrão MVP no ASP.NET para que pelo menos possa testar sua lógica com facilidade.
Além disso, você só precisa ter proficiência em escrever testes de unidade. Se você pratica TDD, seu código é criado para ser testado - em outras palavras, agradável e limpo.
Eu aconselho você a praticar e emparelhar o programa. Enquanto lê:
Ou, para uma primeira visão geral:
fonte
Não.
O conceito por trás dos testes de unidade é baseado em uma premissa que se sabe ser falsa desde que o teste de unidade foi inventado: a ideia de que os testes podem provar que seu código está correto.
Ter muitos testes que passam todos prova uma coisa e apenas uma coisa: que você tem muitos testes que passam todos. Não prova que o que os testes estão testando corresponde à especificação. Isso não prova que seu código está livre de erros que você nunca considerou quando escreveu os testes. (E as coisas que você pensou em testar eram os possíveis problemas em que estava se concentrando, então é provável que você as tenha acertado de qualquer maneira!) E por último, mas não menos importante, isso não prova que os testes, que são eles próprios código, estão livres de bugs. (Siga esse último até sua conclusão lógica e você terminará com tartarugas até o fim .)
Djikstra destruiu o conceito de testes como prova de correção em 1988, e o que ele escreveu permanece tão válido hoje:
O outro problema com o teste de unidade é que ele cria um acoplamento rígido entre seu código e o conjunto de testes. Quando você altera o código, espera-se que apareçam alguns erros que quebrariam alguns testes. Mas se você estiver alterando o código porque os requisitos foram alterados, você terá muitos testes com falha e precisará revisar manualmente cada um deles e decidir se o teste ainda é válido. (E também é possível, embora menos comum, que um teste existente que deveria ser inválido ainda passe, porque você esqueceu de alterar algo que precisava ser alterado.)
O teste de unidade é apenas o mais recente de uma longa linha de modismos de desenvolvimento que promete facilitar a gravação de código de trabalho sem ser um bom programador. Nenhum deles conseguiu cumprir sua promessa, e nem essa. Simplesmente não há atalho para realmente saber como escrever código de trabalho .
Existem alguns relatos de testes automatizados sendo realmente úteis nos casos em que a estabilidade e a confiabilidade são de suma importância. Por exemplo, o projeto de banco de dados SQLite. Mas o que é necessário para atingir seu nível de confiabilidade é altamente antieconômico para a maioria dos projetos: uma taxa de código SQLite de teste para real de quase 1200: 1. A maioria dos projetos não pode pagar por isso e nem precisa disso.
fonte
but if the test itself is buggy, then you have false confidence
e se o testador manual não executar seu trabalho corretamente, você também terá uma confiança falsa.Se você já viu o benefício de escrever um método principal para testar algum pequeno pedaço de código da escola, o teste de unidade é a versão profissional / empresarial dessa mesma prática.
Imagine também a sobrecarga da criação do código, iniciando o servidor da Web local, navegando até a página em questão, inserindo os dados ou configurando a entrada para a semente de teste apropriada, enviando o formulário e analisando os resultados ... vs compilação e batida o botão nUnit run.
Aqui está uma imagem divertida também ...
Encontrei esta imagem aqui:
http://www.howtogeek.com/102420/geeks-versus-non-geeks-when-doing-repetitive-tasks-funny-chart/
fonte
Exception
e cole um para que seus dados não sejam confirmados. Eu digo SIM ao teste de unidade.Atualmente, o teste de unidade tem uma mística nisso. As pessoas o tratam como se 100% da cobertura de teste fosse um santo graal e como se o teste de unidade fosse a única maneira verdadeira de desenvolver software.
Eles estão perdendo o objetivo.
Teste de unidade não é a resposta. Teste é.
Agora, sempre que essa discussão surgir, alguém (muitas vezes até eu) fará a citação de Dijkstra: "O teste do programa pode demonstrar a presença de bugs, mas nunca demonstra a sua ausência". Dijkstra está certo: o teste não é suficiente para provar que o software funciona como pretendido. Mas é necessário : em algum nível, deve ser possível demonstrar que o software está fazendo o que você deseja.
Muitas pessoas testam à mão. Até os entusiastas do TDD fazem testes manuais, embora às vezes não o admitam. Não pode ser ajudado: pouco antes de você entrar na sala de conferências para demonstrar seu software ao seu cliente / chefe / investidores / etc., Você o percorrerá manualmente para garantir que funcione. Não há nada de errado com isso, e de fato seria louco esperar que tudo corra bem sem executá-lo manualmente - ou seja, testá-lo - mesmo se você tiver 100% de cobertura de teste de unidade e a maior confiança em seus testes .
Mas o teste manual, mesmo que seja necessário para a criação de software, raramente é suficiente . Por quê? Porque o teste manual é tedioso, demorado e realizado por humanos. E os seres humanos são notoriamente ruins em realizar tarefas tediosas e demoradas: evitam fazê-las sempre que possível e geralmente não as fazem bem quando são forçadas a fazê-lo.
As máquinas , por outro lado, são excelentes para executar tarefas tediosas e demoradas. Afinal, foi para isso que os computadores foram inventados.
Portanto, o teste é crucial, e o teste automatizado é a única maneira sensata de garantir que seus testes sejam empregados de forma consistente. E é importante testar e testar novamente, à medida que o software é desenvolvido. Outra resposta aqui observa a importância do teste de regressão . Devido à complexidade dos sistemas de software, alterações freqüentemente aparentemente inócuas em uma parte do sistema causam alterações indesejadas (ou seja, bugs) em outras partes do sistema. Você não pode descobrir essas alterações indesejadas sem alguma forma de teste. E se você deseja ter dados confiáveis sobre seus testes, deve realizar seus testes de maneira sistemática, o que significa que você deve ter algum tipo de sistema de teste automatizado.
O que tudo isso tem a ver com o teste de unidade? Bem, devido à sua natureza, os testes de unidade são executados pela máquina, não por um ser humano. Portanto, muitas pessoas têm a falsa impressão de que o teste automatizado é igual ao teste de unidade . Mas isso não é verdade: os testes de unidade são apenas pequenos testes automatizados.
Agora, qual é o valor em pequenos testes automatizados? A vantagem é que eles testam os componentes de um sistema de software isoladamente , o que permite um direcionamento mais preciso dos testes e ajuda na depuração . Mas o teste de unidade não significa intrinsecamente testes de qualidade superior . Muitas vezes, leva a testes de qualidade mais alta, devido à cobertura do software em um nível mais fino de detalhes. Mas é possível testar completamente o comportamento de apenas um sistema completo, e não suas partes compostas, e ainda testá-lo completamente.
Mas mesmo com 100% de cobertura de teste de unidade, um sistema ainda pode não ser completamente testado. Como os componentes individuais podem funcionar perfeitamente isolados, ainda assim falham quando usados juntos. Portanto , o teste de unidade, embora seja muito útil, não é suficiente para garantir que o software funcione conforme o esperado. De fato, muitos desenvolvedores complementam os testes de unidade com testes de integração automatizados, testes funcionais automatizados e testes manuais.
Se você não vê valor nos testes de unidade, talvez a melhor maneira de começar seja usando um tipo diferente de teste automatizado. Em um ambiente web, o uso de uma ferramenta de teste de automação de navegador como o Selenium geralmente oferece uma grande vitória para um investimento relativamente pequeno. Depois de mergulhar os dedos dos pés na água, você poderá ver com mais facilidade a utilidade dos testes automatizados. E uma vez que você tem testes automatizados, o teste de unidade faz muito mais sentido, pois fornece uma resposta mais rápida do que grandes testes de integração ou de ponta a ponta, pois você pode direcionar testes apenas para o componente em que está trabalhando no momento.
TL; DR: não se preocupe com o teste de unidade ainda. Apenas se preocupe em testar seu software primeiro.
fonte
Depende
Esta é uma resposta que você verá bastante quando se trata de desenvolvimento de software, mas a utilidade dos testes de unidade realmente depende de quão bem eles são escritos. Um número nominal de testes de unidade que verificam a funcionalidade do aplicativo para teste de regressão pode ser bastante útil; no entanto, uma infinidade de testes simples que verificam o retorno das funções pode ser bastante inútil e fornecer uma falsa sensação de segurança, porque o aplicativo "tem muitos testes de unidade".
Além disso, seu tempo como desenvolvedor é valioso e o tempo gasto escrevendo testes de unidade não é o tempo gasto escrevendo novos recursos. Novamente, isso não significa que você não deve escrever testes de unidade, mas todas as funções públicas precisam de um teste de unidade? Eu diria que a resposta é não. O código que está executando a validação de entrada do usuário precisa de teste de unidade? Muito provavelmente, pois é um ponto de falha comum em aplicativos.
Essa é uma daquelas áreas em que a experiência entra em jogo. Com o tempo, você reconhecerá as partes do aplicativo que poderiam se beneficiar do teste de unidade, mas levará algum tempo para chegar a esse ponto.
fonte
Os projetos realizados para aulas universitárias diferem muito dos aplicativos de negócios que você escreverá no seu trabalho. A diferença é vida útil. Quanto tempo o projeto universitário "vive"? Na maioria dos casos, começa quando você escreve a primeira linha do código e termina quando recebe a sua marca. Você poderia dizer que, efetivamente, ele vive apenas pelo tempo de implementação. "Liberação" é geralmente igual à sua "morte".
O software desenvolvido para os negócios ultrapassa esse ponto de morte do projeto da universidade e continua a viver enquanto os negócios precisarem. O que é muito longo . Quando se fala em dinheiro, ninguém gasta um centavo quebrado para ter um "código mais legal e organizado". Se o software escrito em C há 25 anos ainda funciona e é bom o suficiente (conforme entendido pelas necessidades do proprietário da empresa), espera-se que você o solicite para mantê-lo (adicionando novos recursos, melhorando os antigos - alterando o código-fonte ).
Chegamos a um ponto muito importante - regressão . No local em que trabalho, temos duas equipes mantendo dois aplicativos; um, escrito há cerca de 5 a 6 anos, com muito pouca cobertura para testes de código *, e segundo, versão mais recente do primeiro aplicativo com conjunto de testes completo (unidade, integração e o que não mais). Ambas as equipes têm testadores manuais (humanos) dedicados. Deseja saber quanto tempo leva para introduzir um novo recurso bastante básico para a primeira equipe? 3 a 4 semanas. Metade desse tempo está "verificando se tudo ainda funciona". Este é um tempo ocupado para testadores manuais. Os telefones estão tocando, as pessoas ficam chateadas, algo está quebrado de novo. A segunda equipe geralmente lida com esses problemas em menos de 3 dias.
Eu nunca digo que os testes de unidade tornam seu erro de código propenso, correto ou outras palavras sofisticadas que você pode criar. Nem eles fazem os erros desaparecerem magicamente. Porém, quando combinados com outros métodos de teste automatizado de software, eles tornam os aplicativos muito mais fáceis de manter do que teriam sido. Esta é uma grande vitória.
E por último, mas não menos importante, comentário de Brian, que acho que trata da questão toda:
Porque entre hoje e amanhã, alguém pode fazer pequenas alterações, o que causará uma falha no código do gerador de relatórios tão importante . Os testes aumentam as chances de que você descubra isso antes que o cliente faça um pouco do seu lado.
* Eles introduzem lentamente mais e mais testes em sua base de código, mas todos sabemos como essas coisas geralmente se parecem.
fonte
Isso nem sempre é feito. Trabalhar com elementos da interface do usuário não é bom para os testes de unidade, pois não há uma maneira excelente de verificar programaticamente se as coisas certas acabam na tela nos lugares certos.
Onde aplicável, sim. Eles podem ser muito úteis na verificação de casos específicos de maneira repetível. Eles ajudam a agir como 'atrito' contra mudanças problemáticas e como à prova de falhas quando você está fazendo mudanças melhores.
Uma coisa a notar é que eles geralmente o atrasam.
Esta certo.
Passar um pouco de tempo agora (se bem feito) economizará seu tempo no futuro, pois eles detectam alguns erros, evitam a repetição de alguns erros e permitem que você se sinta um pouco mais confortável ao fazer outras melhorias no código para impedir que ele apodreça.
fonte
Isso porque você nunca programou muito.
Escrever testes de unidade força seu código a se adaptar a uma determinada estrutura mental que é testável, bem documentada e confiável. É muito mais do que você afirma.
simule o acesso ao banco de dados com uma classe simulada que retorna classes de modelo preenchidas com dados bem definidos e codificados. ou preencha um banco de dados de teste com dados do equipamento e trabalhe a partir daí.
Claro que sim. Leia o "Test Driven Development" de Beck primeiro.
Isso deixa você mais lento agora. Mas quando você precisar depurar por horas em vez de dias, você mudará de idéia.
Teste. Confie em mim. Infelizmente, também deve ser uma política de gerenciamento, mas é algo que economiza tempo. Os testes permanecem, eles estão lá, agora e no futuro. Quando você altera a plataforma e executa os testes, e eles ainda funcionam, você sabe que seu material funciona conforme o esperado.
fonte
Edit: É claro que entrei para o TDD pro / con dogpile e pulei a pergunta 1:
1 - Implementando testes de unidade nos formulários da web ASP.net:
Primeiro de tudo, se você acha que pode levá-los ao MVC, lute por ele como um urso da caverna raivoso. Como desenvolvedor front-end / UI, o .net MVC foi o que me ajudou a parar de odiar o .net, para que eu pudesse me concentrar melhor em odiar todas as soluções da Web em Java que já encontrei. Os testes de unidade são problemáticos porque os formulários da Web realmente desfocam as linhas entre o servidor e o lado do cliente. Em qualquer tentativa de fazer testes de unidade, eu colocaria o foco na manipulação de dados e (esperançosamente) presumiria que os formulários da web tratam da normalização da entrada do usuário para você.
2 - Se os testes de unidade valem a pena em primeiro lugar:
Tudo bem, divulgação completa:
Contudo,
Isso significa que não escrevo para o mesmo compilador ou máquina virtual. Eu escrevo para 4-20 interpretações variadas de três idiomas (sim, dois deles meramente declarativos, mas também determinam o espaço físico fundamental da interface do usuário com o qual estou trabalhando de maneiras diferentes às vezes) e o faço desde que as interpretações foram um muito mais variado do que é hoje. E não, eu não sou apenas um garoto que conecta coisas do JQuery para aplicativos descartáveis. Ajudo a criar e manter coisas bastante sofisticadas com muita complexidade de elementos de interface do usuário.
Portanto, sim, existem muitas oportunidades para alguns ajustes aqui e ali para criar uma cascata maciça de falhas se suas habilidades de design forem uma porcaria completa ou se você estiver jogando devs medíocres em grandes quantidades com 1-2 problemas de qualidade.
Meu entendimento do que o TDD deve fazer por você é que os testes são realmente mais para forçar você a considerar o design com mais cuidado e manter o foco nos requisitos. É justo, mas o problema aqui é que ele subverte o que você deve fazer, que é o design para uma interface, para algo sutil, mas fundamentalmente diferente, que é o design para testes de uma interface. A diferença para mim é entre desenhar uma imagem clara de que a mamãe não terá que adivinhar o significado e preencher a página inteira com verde muito rápido, para que você possa ser o primeiro garoto a dar um tapa na mesa e gritar "pronto!" " Ao mudar a prioridade dos resultados sobre o processo e o design, você basicamente incentiva a implementação contínua do código de lixo, que é o que estava na raiz dos seus problemas em primeiro lugar.
E, claro, há o benefício secundário "não é o ponto real", mas frequentemente elogiado, dos próprios testes de unidade, ajudando a detectar erros de regressão. Os defensores do TDD tendem a ser um pouco insolentes sobre se esse é realmente o objetivo ou apenas um efeito colateral bacana, a IMO, porque eles sabem muito bem ou suspeitam pelo menos que isso simplesmente não é suficiente para estabelecer a ausência de bugs no seu código, especialmente em uma linguagem mais dinâmica como JavaScript, na qual supor que você possa prever todos os cenários possíveis em uma longa cadeia de dependências é imprudente.
Há um local para testes automatizados em JS, mas um uso muito melhor do seu tempo do que anexar um teste de unidade a cada 'unidade' do seu código que entra em contato com outro é garantir que você não tenha muitos objetos de lixo que duplicam o trabalho ou cujo uso pretendido é semanticamente ambíguo nele, em primeiro lugar. Você segue o princípio DRY. Você abstrai as coisas para reutilização / portabilidade quando o valor de fazer isso se torna aparente (e nem um minuto antes). Você estabelece processos consistentes e maneiras de fazer as coisas seguindo mais o princípio da cenoura do que da vara (ou seja, é muito fácil usar suas coisas da maneira certa para se incomodar em querer fazer da maneira errada). E pelo amor de todas as coisas, foo and bar, você nunca se envolve em enormes padrões de esquemas de herança em cascata como um meio de reutilização de código.
Todas as opções acima me ajudaram a reduzir os erros difíceis de diagnosticar no meu código de maneira séria e você pode confiar que é uma grande prioridade para alguém que surgiu como desenvolvedor com um conjunto de navegadores que não tinha nada melhor para lhe dizer do que " uh, houve um problema com um objeto do tipo 'Objeto' neste número de linha imaginário em um arquivo não especificado. " (caramba, obrigado IE6) O TDD, na minha linha de trabalho, não incentivaria essas coisas. Mudaria o foco para 100% de resultados sobre o processo, onde o que está entre os pontos A e B não importa realmente, desde que funcione. É um desperdício de tempo que seria melhor aplicado para garantir que seu material seja legível, portátil e fácil de modificar, sem muita quebra de confusão em primeiro lugar.
Ou talvez eu esteja apenas sendo excessivamente mesquinho sobre o paradigma em que estou enraizado, mas, em minha opinião, fazer isso da maneira certa é um uso muito mais eficaz do tempo do que cobrir sua bunda quando você ou todos os outros equipe faz errado. E nada deve forçá-lo a considerar o design, apenas implementando as coisas. O design deve ser o altar de todo programador. E qualquer coisa que "o force" a fazer a coisa certa ou o proteja de si mesmo deve ser vista com a mesma suspeita reservada a garrafas de óleo de cobra, a IMO. O óleo de cobra na TI moderna e no desenvolvimento geral, se você ainda não sabe, é vendido por tonelada líquida.
fonte
Na minha experiência, os testes de unidade são realmente muito úteis quando você começa com eles e permanece com eles, isto é, Desenvolvimento Orientado a Testes. Aqui está o porquê:
Os testes de unidade forçam você a pensar sobre o que deseja e como verificar se o conseguiu, antes de escrever o código . Em um cenário TDD, você escreve o teste primeiro. Portanto, você precisa saber o que o código que você está prestes a escrever precisa fazer e como verificar se ele foi bem-sucedido, para escrever um teste "vermelho" que você torna "verde" escrevendo o código em passe isso. Em muitos casos, isso força você a pensar um pouco mais sobre o algoritmo que está prestes a escrever para passar neste teste, o que é sempre bom, pois reduz erros de lógica e "casos de canto". Enquanto você está escrevendo o teste, está pensando "como isso pode falhar" e "o que não estou testando aqui", o que leva a um algoritmo mais robusto.
Os testes de unidade forçam você a pensar em como o código que você está prestes a escrever será consumido . Antes de aprender o TDD, houve MUITAS vezes em que escrevi código esperando que uma dependência funcionasse de uma maneira e depois recebi uma dependência escrita por um colega que trabalhava de uma maneira completamente diferente. Embora isso ainda seja possível com o TDD, o teste de unidade que você está escrevendo o força a pensar em como você deseja usar o objeto que está escrevendo, porque é um exemplo de uso do referido objeto. Esperamos que você escreva o objeto de maneira que seja fácil de consumir e, portanto, se adapte, se necessário (embora a programação para interfaces predefinidas seja uma solução geral melhor para esse problema que não requer TDD).
Os testes de unidade permitem "codificar por teste" . Uma ferramenta de refatoração como o ReSharper pode ser sua melhor amiga, se você permitir. Você pode usá-lo para definir o esqueleto da nova funcionalidade enquanto define o uso em um teste.
Por exemplo, suponha que você precise criar um novo objeto MyClass. Você começa criando uma instância do MyClass. "Mas o MyClass não existe!", Reclama ReSharper. "Então crie", você diz, pressionando Alt + Enter. E pronto, você tem sua definição de classe. Na próxima linha do código de teste, você chama um método MyMethod. "Mas isso não existe!", Diz ReSharper. "Então crie", você repete, com outro Alt + Enter. Com algumas teclas pressionadas, você definiu o "esqueleto" do seu novo código. À medida que você aprimora o uso, o IDE avisa quando algo não se encaixa, e geralmente a solução é simples o suficiente para que o IDE ou uma ferramenta que se conecte a ele saiba como corrigi-lo.
Exemplos mais extremos estão em conformidade com o modelo "Triple-A"; "Organize, aja, afirme". Configure tudo, execute a lógica real que você está testando e depois afirme que a lógica está correta. Codificando dessa maneira, é muito natural codificar a solução no teste; depois, com algumas teclas pressionadas, você pode extrair essa lógica e colocá-la em algum lugar onde possa ser usada no código de produção, e depois fazer pequenas alterações no teste que apontam para o novo local da lógica. Fazer isso dessa maneira obriga a arquitetar o código de maneira modular e fácil de reutilizar, porque as unidades que você está testando ainda devem estar acessíveis.
Os testes de unidade executam muitas ordens de magnitude mais rapidamente do que qualquer teste manual que você possa imaginar. Há um ponto, muito rapidamente atendido no caso de projetos maiores, em que o tempo gasto em testes de unidade começa a se pagar, reduzindo o tempo gasto em testes manuais. Você sempre deve executar o código que acabou de escrever. Tradicionalmente, você fazia isso manualmente, iniciando um programa grande, navegando pela interface do usuário para configurar a situação para a qual alterou o comportamento e depois verificando os resultados novamente através da interface do usuário ou na forma de dados produzidos. Se o código tiver TDD, basta executar os testes de unidade. Garanto que, se você estiver escrevendo bons testes de unidade, a última opção será muitas vezes mais rápida que a anterior.
Testes de unidade capturam regressão . Novamente, houve muitas vezes antes que eu aprendesse TDD em que entrei, fiz o que eu pensava ser uma mudança cirúrgica em um pedaço de código, verifiquei que a mudança corrigia um comportamento incorreto (ou produzia um novo comportamento desejado) na situação relatada , e fez o check-in para liberação, apenas para descobrir que a alteração quebrou outro caso de canto em um módulo completamente diferente que, por acaso, reutilizou o mesmo bloco de código. Em um projeto TDDed, eu posso escrever um teste para verificar uma alteração que estou prestes a fazer, fazer a alteração e executar o conjunto completo. Se todos os outros usos do código foram TDDed e minha alteração quebrou alguma coisa, os testes para esses outras coisas vão falhar, e eu posso investigar.
Se os desenvolvedores precisassem encontrar e testar manualmente todas as linhas de código que poderiam ser afetadas por uma alteração em potencial, nada seria feito porque o custo de determinar o impacto de uma alteração tornaria a alteração inviável. No mínimo, nada seria SÓLIDO e, portanto, facilmente mantido, porque você nunca ousaria tocar em algo que possa ser usado em vários lugares; em vez disso, você lançaria sua própria solução de alteração muito semelhante, mas incorporando sua menor para este caso, violando o SRP e provavelmente o OCP, e lentamente transformando sua base de código em uma colcha de retalhos.
Os testes de unidade moldam a arquitetura de uma maneira tipicamente vantajosa . Testes de unidade são testes executados isoladamente de qualquer outra lógica. Para poder testar seu código de unidade, você deve escrever o código da maneira que puderisolá-lo. Boas decisões de projeto, como acoplamentos frouxos e injeção de dependência, eliminam naturalmente o processo TDD; as dependências devem ser injetadas para que, em um teste, você possa injetar um "mock" ou "stub" que produza a entrada ou manipula a saída para a situação que está sendo testada sem criar "efeitos colaterais". A mentalidade de "primeiro uso" do TDD geralmente leva à "codificação para interfaces", a essência do acoplamento flexível. Esses bons princípios de design permitem que você faça alterações na produção, como substituir uma classe inteira, sem exigir que grandes quantidades da base de código sejam alteradas para se adaptar.
Testes de unidade mostram que o código funciona, em vez de provar que o código funciona . À primeira vista, você pode pensar que é uma desvantagem; certamente a prova é melhor que a demonstração? A teoria é ótima; teoria computacional e algorítmica é a base do nosso trabalho. Porém, uma prova matemática de correção de um algoritmo não é prova de correção da implementação . Uma prova matemática mostra apenas que o código aderente ao algoritmo deve estar correto. Um teste de unidade mostra que o código realmente escrito faz o que você pensou que faria e, portanto, é prova de que está correto. Isso geralmente tem muito mais valor do que uma prova teórica.
Agora, tudo o que foi dito, há desvantagens no teste de unidade:
Você não pode testar tudo. Você pode arquitetar seu sistema para minimizar o número de LOC não cobertos por um teste de unidade, mas simplesmente haverá certas áreas do sistema que não podem ser testadas em unidade. Sua camada de acesso a dados pode ser ridicularizada quando usada por outro código, mas a própria camada de acesso a dados contém muitos efeitos colaterais e, normalmente, não é viável fazer o teste de unidade muito (a maioria?) De um Repositório ou DAO. Da mesma forma, o código que usa arquivos, configura conexões de rede etc. tem efeitos colaterais integrados e você simplesmente não pode testar a unidade de linha de código que faz isso. Os elementos da interface do usuário geralmente não podem ser testados em unidade; você pode testar os códigos por trás de métodos como manipuladores de eventos, pode construir construtores de teste de unidade e verificar se os manipuladores estão conectados, mas simplesmente não há substituto no código para um usuário clicar com o mouse em um elemento gráfico específico e assistir ao chamado do manipulador. Atingir esses limites entre o que pode e o que não pode ser adequadamente testado em unidade é chamado de "raspar a borda da caixa de areia"; além desse ponto, você está limitado ao uso de testes de integração, testes de aceitação automatizados e testes manuais para verificar o comportamento.
Muitas vantagens do teste de unidade não se aplicam sem TDD. É perfeitamente possível escrever código, depois escreva testes que exercitam o código. Eles ainda são "testes de unidade", no entanto, ao escrever o código primeiro, você perde muitas das vantagens inerentes ao desenvolvimento do "teste primeiro": o código não é necessariamente arquitetado de uma maneira que possa ser facilmente testada ou mesmo usada na produção. ; você não recebe o processo de "verificação dupla" inerente ao escrever o teste e pensar no que você não estava pensando; você não codifica testando; e se você escrever um código, teste-o manualmente e veja-o funcionar; em seguida, codifique um teste de unidade que falha, o que está errado, o código ou o teste? Suas principais vantagens são a prevenção de regressão (você será alertado quando o código que passou anteriormente em seus testes agora falhar) e a verificação em alta velocidade em comparação aos testes manuais. A perda de TDD '
O teste de unidade introduz uma sobrecarga . Simplesmente, você está escrevendo um código para testar o código que está escrevendo. Isso necessariamente aumentará o LOC total de um projeto de desenvolvimento e, sim, o LOC para testes pode exceder o LOC do projeto real. Desenvolvedores e não desenvolvedores ingênuos analisarão esse estado de coisas e dirão que os testes são uma perda de tempo.
O teste de unidade requer disciplina. É necessário escrever testes que exercitem adequadamente a base de código (boa cobertura de código), executar regularmente (como sempre que você fizer uma alteração, o conjunto completo deve ser executado) e manter tudo "verde" ( todos os testes foram aprovados). Quando as coisas quebram, você deve corrigi-las fixando o código que não atende às expectativas ou atualizando as expectativas dos testes. Se você alterar os testes, deverá perguntar "por que" e vigiar muito bem a si mesmo; é incrivelmente tentador simplesmente alterar afirmações com falha para corresponder ao comportamento atual ou simplesmente remover testes com falha; mas, esses testes devem se basear nos requisitos e, quando os dois não correspondem, você tem um problema. Se essas coisas não forem feitas,
O teste de unidade requer mais equipamentos. A solução usual para a necessidade de disciplina acima, e uma tendência natural dos humanos de se tornarem preguiçosos e compactos, é um "build-bot" executando um pacote de software de "Integração Contínua", como TeamCity, CruiseControl, etc., que executa testes de unidade, calcula métricas de cobertura de código e possui outros controles, como "triple-C" (conformidade de convenção de codificação, à la FxCop). O hardware para o build-bot deve ter um desempenho razoavelmente bom (caso contrário, não acompanhará a taxa de check-ins de código que a equipe média fará), e os procedimentos de check-in no bot devem ser atualizados (se uma nova biblioteca de testes de unidade é criada, scripts de construção que executam testes de unidade devem ser alterados para procurar nessa biblioteca). Isso é menos trabalho do que parece, mas normalmente requer algum conhecimento técnico por parte de pelo menos algumas pessoas da equipe que sabem como funcionam os detalhes de vários processos de construção (e, portanto, podem automatizá-los em scripts e manter esses scripts). Também requer disciplina na forma de prestar atenção quando a compilação "quebrar" e corrigir o que causou a compactação (corretamente) antes de fazer o check-in de algo novo.
O teste de unidade pode forçar a arquitetura do código de maneira não ideal . Embora o TDD seja tipicamente bom para a modularidade e reutilização do código, pode ser prejudicial à acessibilidade adequada do código. Objetos e membros, colocados em bibliotecas de produção, não podem ser privados ou internos se forem usados diretamente por testes de unidade. Isso pode causar problemas quando outros codificadores, agora vendo um objeto, tentam usá-lo quando deveriam usar algo mais presente na biblioteca. As revisões de código podem ajudar com isso, mas podem ser uma preocupação.
O teste de unidade geralmente proíbe estilos de codificação de "desenvolvimento rápido de aplicativos". Se você está escrevendo testes de unidade, não está codificando "rápido e solto". Isso normalmente é uma coisa boa, mas quando você está dentro de um prazo imposto fora do seu controle ou está implementando uma mudança de escopo muito pequeno, e a parte interessada (ou seu chefe) está se perguntando por que todo esse lixo deve acontecer apenas para alterar uma linha de código, pode ser inviável escrever e manter o conjunto de testes de unidade adequado. Os processos ágeis geralmente ajudam nisso, permitindo que os desenvolvedores digam os requisitos de tempo; lembre-se, tudo o que o vendedor precisa fazer é dizer "sim, podemos" e eles recebem a verificação da comissão, a menos que o processo envolva as pessoas que realmente precisam fazer o trabalho dizendo "não, não podemos" e prestando atenção. Mas nem todos são ágeis e o Agile tem suas próprias limitações.
fonte
Testes de unidade são úteis quando usados corretamente; Existem vários problemas com sua lógica.
"Quando estou desenvolvendo, passo por muitas tentativas e erros", disse Kevin.
Veja a programação por coincidência. É melhor entender o que um código deve fazer e provar que ele é feito através de um teste de unidade. Não assuma que um código funcione simplesmente porque a interface do usuário não quebrou quando você executou o programa!
s writing unit tests for ASP.NET web forms something that is done often
Não tenho conhecimento de dados estatísticos para dizer com que frequência as pessoas testam formulários da web. Isso não importa. A interface do usuário é difícil de testar e os testes de unidade também não devem ser acoplados a uma interface do usuário. Separe sua lógica em camadas, bibliotecas de classes que podem ser testadas. Teste a interface do usuário separadamente da lógica de back-end.
So, question number 2: Would you guys advise me to start writing unit tests?
Sim. Depois que você se acostuma, eles aceleram você. A manutenção é muito mais demorada e cara do que a fase inicial de desenvolvimento. A manutenção é muito auxiliada nos testes de unidade, mesmo nos testes iniciais e na correção de erros.
fonte
Em um nível prático, os testes de unidade podem ser extremamente úteis por um motivo muito importante: você pode testar um bit de código por vez.
Quando você está escrevendo uma sequência inteira de etapas complexas e as depura no final, você tende a encontrar muitos erros, e o processo geralmente é mais difícil porque você está mais adiantado no processo. No Visual Studio, você pode gerar um teste rápido, alterá-lo um pouco e executar APENAS esse teste . Você sabe que, por exemplo, um método que chama esse método pode confiar nele. Portanto, aumenta a confiança.
Os testes de unidade não provam que seu programa está correto! : Os testes de unidade verificam regressões no código confidencial e permitem testar novos métodos que você escreve.
Os testes de unidade não têm como objetivo testar os front-ends : pense em um teste de unidade como o pequeno projeto que você cria para testar um novo método que você está escrevendo ou algo assim, não como um tipo de condição que seu código precisa atender.
O teste de unidade funciona muito bem em ambientes colaborativos : se eu tiver que fornecer um método para um colega que está usando uma tecnologia completamente diferente da minha, como, por exemplo, ele está chamando a partir do iOS, eu posso escrever rapidamente um teste de unidade para ver se o método que ele deseja a) Recupera os dados corretos b) Executa de acordo com suas especificações c) Não possui gargalos desagradáveis.
fonte
Uma coisa que parece não ser abordada é a complexidade de testar diferentes tipos de código.
Quando você lida com itens com entradas e saídas simples, geralmente é fácil fazer o teste de unidade e, se os testes forem escolhidos tendo em mente os casos extremos do código que está sendo testado, eles lhe darão muita confiança de que estão certos. Não escrever testes para esse código seria uma loucura. (Observe que a maioria dos códigos inseridos nas bibliotecas atende a esse critério.)
No entanto, em outros casos, você acaba criando enormes simulações para testar, porque o código está reproduzindo dados subjacentes complexos (geralmente um banco de dados, mas não precisa ser) ou produz dados de saída muito complexos (pense em uma rotina que muda um valor inicial em um nível de jogo para um exemplo bastante extremo) e o teste de unidade não é tão útil. Cobrir tudo em seus casos de teste geralmente é um sonho, e quando você encontra um bug, quase sempre é um caso em que você nunca pensou e, portanto, não poderia ter construído um teste para isso.
Não há balas de prata, qualquer coisa retratada como uma bala de prata não é tão boa quanto afirmam os defensores, mas isso não significa que seja inútil.
fonte
Escrever testes de unidade para aplicativos de formulários da Web do ASP.NET NÃO é comum e muito difícil de realizar. No entanto, isso não significa que o projeto deve ignorá-lo.
Os testes de unidade são
corner stones
aplicativos de missão crítica e fornecem confiabilidade e tranquilidade de que a funcionalidade principal executa conforme o esperado.Na verdade, você pode introduzir testes de unidade com muito mais facilidade com um padrão ASP.NET MVP que pode ser usado no desenvolvimento de formulários da web. Introduzirá separação de preocupações e
ability to write essential unit tests
.Algumas referências que podem ser úteis para procurar são:
fonte
O objetivo dos testes de unidade é permitir que você altere seu código com segurança (refatoração, aprimoramento etc.) sem o medo de poder quebrar algo dentro do sistema. Isso se mostra muito útil para aplicativos grandes, quando você realmente não conhece todos os efeitos de sua alteração de código (apesar do acoplamento fraco).
fonte
É minha experiência que sim , testes de unidade são úteis.
O Teste de Unidade trata da segregação de partes do código que você escreve e garante que elas funcionem isoladamente. Esse isolamento pode realmente envolver a criação de objetos falsos ou simulados para conversar com o objeto que você está testando, ou não. Depende muito da arquitetura do seu objeto.
O teste de unidade concede vários benefícios:
Principalmente, isso garante que as unidades testadas funcionem da maneira que você, desenvolvedor, acha que elas devem funcionar. Embora isso seja menor do que parece: não significa necessariamente que o objeto esteja funcionando corretamente; só que está funcionando como você acha que deve funcionar, é uma afirmação muito mais forte do que o método de tentativa e erro necessário sem o teste de unidade.
Além disso, garante que as unidades continuem funcionando da maneira que você, o desenvolvedor, pensou que deveria funcionar. O software é alterado e isso pode afetar as unidades de maneiras inesperadas.
Outro efeito colateral é que isso significa que as unidades que testam fazer o trabalho de forma isolada. Isso geralmente significa que você começa a programar para interfaces em vez de classes concretas, reduzindo o acoplamento e aumentando a coesão: todas as características comuns do bom design. Sim: apenas permitir que suas unidades de código tenham testes de unidade naturalmente melhorará o design do seu código.
Contudo...
O teste de unidade não é o fim do teste. Outros tipos de teste ainda são necessários. Por exemplo, mesmo quando você mostra que as unidades funcionam da maneira que você espera que funcionem, você ainda precisa mostrar que cada unidade funciona da maneira que as unidades que falam com ela esperam que funcione. Ou seja, seus componentes se integram corretamente?
fonte
Para aplicativos simples com um pequeno número de camadas para testar (Janela principal -> submenu), talvez seja necessário compilar para executar para verificar as alterações.
Para aplicativos maiores, nos quais é necessária uma navegação de 30 anos para acessar a página que você está testando, isso acaba sendo muito caro.
fonte
Quero adicionar um novo lado (na verdade um antigo) a isso: testes de unidade não são tão úteis se o seu código for bem projetado .
Sei que a maioria dos programadores não faz mais o design de programas, ainda o faço, e achei os testes de unidade uma necessidade bastante demorada para se encaixar em uma cultura TDD, mas até agora, só encontrei 1 a 2 menores bugs por milhares de linhas de testes do meu código - não apenas o que escrevi, mas o que os testadores oficiais também escreveram.
Eu acho que você também não fará mais o design de programas - o pessoal atual o pressionará para que não o faça -, mas talvez valha a pena lembrar que o teste de unidade é um método de eficiência muito, muito baixa, comparado ao design.
Este é um argumento dijsktraiano: o teste de unidade só pode ser executado em um programa que seja detalhado o suficiente para ser executado.
Se você desenhar fluxogramas / diagramas de estado / ação, diagramas de seqüência, inventários de objetos (e último E menos, diagramas de classe) para o seu código antes de realmente escrevê-lo, poderá eliminar a maioria dos bugs potencialmente ameaçadores apenas rastreando suas linhas e verificando seus nomes.
Atualmente, os diagramas de classes são gerados a partir do código, contendo centenas, às vezes milhares de classes e são completamente inutilizáveis - qualquer coisa que contenha mais de 15 elementos está além do reconhecimento humano.
Você precisa saber o que 10 + -5 classes importam ou o que você faz no momento e poder verificar seu código de vários pontos de vista, cada diagrama representando EXATAMENTE os pontos de vista que você está vendo, e você eliminará milhares de bugs no papel.
há muito mais fácil ...
Além disso, descobri que meus aplicativos são mais utilizáveis, se vierem diretamente de casos de uso ... se os casos de uso foram escritos corretamente (assunto do verbo ACTOR, o Mantenedor solicita a abertura do caixa eletrônico) ...
Eu fiz código com 95% + de coberturas de código. Claro, às vezes faço testes de unidade, esp. para verificações de limites nos cálculos, mas ainda não encontrei regressões sérias (sérias: não são eliminadas em 24 horas) por não usar testes de unidade, mesmo para refatorações.
Às vezes eu não faço uma única linha de código por 3-4 dias seguidos, apenas desenhando. Então, em um dia, digito 1500-2000 linhas. No dia seguinte, a maioria está pronta para produção. Às vezes, os testes de unidade são escritos (com mais de 80% da cobertura), às vezes (além disso) os testadores são solicitados a tentar quebrá-lo, toda vez que algumas pessoas são solicitadas a revisá-lo olhando para ele.
Ainda estou para ver esses testes de unidade encontrando alguma coisa.
Eu gostaria que o pensamento de design substituísse o TDD ... mas o TDD é muito mais fácil, é como ir com uma marreta ... o projeto precisa de pensamento, e você fica fora do teclado na maioria das vezes.
fonte