Usando C #, preciso de uma classe chamada User
que possua nome de usuário, senha, sinalizador ativo, nome, sobrenome, nome completo, etc.
Deve haver métodos para autenticar e salvar um usuário. Acabei de escrever um teste para os métodos? E eu preciso me preocupar em testar as propriedades, pois elas são getter e setters da .Net?
c#
unit-testing
tdd
nbro
fonte
fonte
Respostas:
Muitas ótimas respostas para isso também estão na minha pergunta: " Iniciando TDD - Desafios? Soluções? Recomendações? "
Posso recomendar também que dê uma olhada no meu post no blog (que foi parcialmente inspirado pela minha pergunta), tenho um bom feedback sobre isso. Nomeadamente:
Espero que isso signifique que podemos seguir em frente "getters and setters" :)
fonte
Teste seu código, não o idioma.
Um teste de unidade como:
só é útil se você estiver escrevendo um compilador e houver uma chance diferente de zero de que seu
instanceof
método não esteja funcionando.Não teste coisas que você pode confiar no idioma para impor. No seu caso, eu focaria nos métodos de autenticação e salvamento - e escreveria testes para garantir que eles pudessem lidar com valores nulos em qualquer um ou todos esses campos normalmente.
fonte
Isso me levou a testes de unidade e me deixou muito feliz
Nós apenas começamos a fazer testes de unidade. Durante muito tempo, sabia que seria bom começar a fazê-lo, mas não fazia ideia de como começar e, mais importante, o que testar.
Em seguida, tivemos que reescrever uma parte importante do código em nosso programa de contabilidade. Essa parte era muito complexa, pois envolvia muitos cenários diferentes. A parte da qual estou falando é um método para pagar faturas de venda e / ou compra já inseridas no sistema contábil.
Só não sabia como começar a codificá-lo, pois havia muitas opções de pagamento diferentes. Uma fatura pode ser de US $ 100, mas o cliente transferiu apenas US $ 99. Talvez você tenha enviado faturas de vendas a um cliente, mas também tenha adquirido desse cliente. Então você o vendeu por US $ 300, mas você comprou por US $ 100. Você pode esperar que seu cliente pague US $ 200 para liquidar o saldo. E se você vendesse por US $ 500, mas o cliente pagasse apenas US $ 250?
Então, eu tinha um problema muito complexo para resolver com muitas possibilidades de que um cenário funcionasse perfeitamente, mas estaria errado em outro tipo de combinação de invocação / pagamento.
Foi aqui que os testes de unidade foram realizados em socorro.
Comecei a escrever (dentro do código de teste) um método para criar uma lista de faturas, tanto para vendas quanto para compras. Então, escrevi um segundo método para criar o pagamento real. Normalmente, um usuário insere essas informações por meio de uma interface do usuário.
Depois, criei o primeiro TestMethod, testando um pagamento muito simples de uma única fatura sem descontos no pagamento. Toda a ação no sistema aconteceria quando um pagamento bancário fosse salvo no banco de dados. Como você pode ver, criei uma fatura, criei um pagamento (uma transação bancária) e salvei a transação no disco. Nas minhas afirmações, coloco quais devem ser os números corretos que terminam na transação bancária e na fatura vinculada. Verifico o número de pagamentos, os valores do pagamento, o valor do desconto e o saldo da fatura após a transação.
Após a execução do teste, eu iria ao banco de dados e verificaria se o que eu esperava estava lá.
Depois que escrevi o teste, comecei a codificar o método de pagamento (parte da classe BankHeader). Na codificação, eu apenas me preocupei com o código para fazer o primeiro teste passar. Ainda não pensei nos outros cenários mais complexos.
Eu executei o primeiro teste, corrigi um pequeno bug até que meu teste passasse.
Então comecei a escrever o segundo teste, desta vez trabalhando com um desconto de pagamento. Depois de escrever o teste, modifiquei o método de pagamento para oferecer suporte a descontos.
Ao testar a correção com um desconto de pagamento, também testei o pagamento simples. Ambos os testes devem passar, é claro.
Depois, trabalhei até os cenários mais complexos.
1) Pense em um novo cenário
2) Escreva um teste para esse cenário
3) Execute esse teste único para ver se passaria
4) Caso contrário, eu depuraria e modificaria o código até que ele passasse.
5) Ao modificar o código, continuei executando todos os testes
Foi assim que consegui criar meu método de pagamento muito complexo. Sem o teste de unidade, eu não sabia como começar a codificar, o problema parecia esmagador. Com o teste, eu poderia começar com um método simples e estendê-lo passo a passo com a garantia de que os cenários mais simples ainda funcionariam.
Tenho certeza de que o uso do teste de unidade me salvou alguns dias (ou semanas) de codificação e garante mais ou menos a correção do meu método.
Se depois pensar em um novo cenário, posso adicioná-lo aos testes para ver se está funcionando ou não. Caso contrário, posso modificar o código, mas ainda assim tenha certeza de que os outros cenários ainda estão funcionando corretamente. Isso economizará dias e dias na fase de manutenção e correção de erros.
Sim, mesmo o código testado ainda pode ter erros se um usuário faz coisas que você não pensou ou o impediu de fazer
Abaixo estão apenas alguns dos testes que criei para testar minha forma de pagamento.
fonte
Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
Se eles realmente são triviais, não se preocupe em testar. Por exemplo, se eles são implementados assim;
Se, por outro lado, você estiver fazendo algo inteligente (como criptografar e descriptografar a senha no getter / setter), faça um teste.
fonte
A regra é que você precisa testar cada parte da lógica que escreve. Se você implementou alguma funcionalidade específica nos getters e setters, acho que vale a pena testar. Se eles apenas atribuírem valores a alguns campos particulares, não se preocupe.
fonte
Esta questão parece ser uma questão de onde se pode traçar quais métodos são testados e quais não.
Os levantadores e os levantadores para atribuição de valor foram criados com consistência e crescimento futuro em mente, e prevendo que em algum momento no caminho o levantador / levantador possa evoluir para operações mais complexas. Faria sentido implementar testes unitários desses métodos, também por uma questão de consistência e crescimento futuro.
A confiabilidade do código, especialmente durante as alterações para adicionar funcionalidade adicional, é o objetivo principal. Eu não estou ciente de que alguém já foi demitido por incluir setters / getters na metodologia de teste, mas estou certo de que existem pessoas que desejavam ter testado métodos que eles conheciam ou que podem lembrar que eram simples invólucros set / get, mas isso não era mais o caso.
Talvez outro membro da equipe tenha expandido os métodos set / get para incluir a lógica que agora precisa ser testada, mas não criou os testes. Mas agora seu código está chamando esses métodos e você não sabe que eles mudaram e precisam de testes detalhados, e os testes que você faz no desenvolvimento e no controle de qualidade não acionam o defeito, mas dados comerciais reais no primeiro dia do lançamento acioná-lo.
Os dois companheiros de equipe agora debaterão sobre quem deixou a bola cair e não conseguiu fazer testes de unidade quando o set / se transformou para incluir lógica que pode falhar, mas não é coberta por um teste de unidade. O companheiro de equipe que originalmente escreveu o set / gets terá mais facilidade em sair dessa limpeza se os testes forem implementados desde o primeiro dia no set / gets simples.
Minha opinião é que alguns minutos de tempo "desperdiçado" cobrindo TODOS os métodos com testes de unidade, mesmo que triviais, podem economizar dias de dor de cabeça no caminho e perda de dinheiro / reputação dos negócios e perda do emprego de alguém.
E o fato de você envolver métodos triviais com testes de unidade pode ser visto por esse colega de equipe júnior quando eles mudam os métodos triviais para outros não triviais e os solicitam a atualizar o teste, e agora ninguém está com problemas porque o defeito foi contido de alcançar a produção.
A maneira como codificamos e a disciplina que pode ser vista em nosso código podem ajudar os outros.
fonte
Outra resposta canônica. Creio que isto de Ron Jeffries:
fonte
Testar o código padrão é uma perda de tempo, mas como Slavo diz, se você adicionar um efeito colateral aos seus getters / setters, deverá escrever um teste para acompanhar essa funcionalidade.
Se você está desenvolvendo um desenvolvimento orientado a testes, escreva primeiro o contrato (por exemplo, interface) e, em seguida, escreva os testes para exercitar a interface que documenta os resultados / comportamentos esperados. Em seguida, escreva seus métodos, sem tocar no código dos testes de unidade. Por fim, pegue uma ferramenta de cobertura de código e verifique se seus testes exercitam todos os caminhos lógicos em seu código.
fonte
Código realmente trivial, como getters e setters que não têm comportamento extra, além de definir um campo privado, é um exagero a ser testado. No 3.0, o C # ainda possui um pouco de açúcar sintático, onde o compilador cuida do campo privado, para que você não precise programar isso.
Geralmente escrevo muitos testes muito simples para verificar o comportamento que espero das minhas aulas. Mesmo que seja simples, como adicionar dois números. Eu mudo muito entre escrever um teste simples e escrever algumas linhas de código. A razão para isso é que eu posso mudar o código sem ter medo de quebrar as coisas em que não pensei.
fonte
Você deveria testar tudo. No momento, você tem getters e setters, mas um dia você pode alterá-los um pouco, talvez para validar ou algo mais. Os testes que você escrever hoje serão usados amanhã para garantir que tudo continue funcionando normalmente. Ao escrever o teste, você deve esquecer considerações como "agora é trivial". Em um contexto ágil ou orientado a teste, você deve testar assumindo refatoração futura. Além disso, você tentou inserir valores realmente estranhos, como sequências extremamente longas ou outro conteúdo "ruim"? Bem, você deve ... nunca assumir o quanto seu código pode ser abusado no futuro.
Geralmente, acho que escrever exaustivos testes para o usuário é cansativo. Por outro lado, embora ele sempre ofereça informações valiosas sobre como o aplicativo deve funcionar e ajude a descartar suposições fáceis (e falsas) (como: o nome do usuário sempre terá menos de 1.000 caracteres).
fonte
Para módulos simples que podem acabar em um kit de ferramentas ou em um tipo de projeto de código aberto, você deve testar o máximo possível, incluindo os getters e setters triviais. O que você deseja ter em mente é que gerar um teste de unidade ao escrever um módulo específico é bastante simples e direto. Adicionar getters e setters é um código mínimo e pode ser tratado sem muita reflexão. No entanto, depois que seu código é colocado em um sistema maior, esse esforço extra pode protegê-lo contra alterações no sistema subjacente, como alterações de tipo em uma classe base. Testar tudo é a melhor maneira de ter uma regressão completa.
fonte
Não faz mal escrever testes de unidade para seus getters e setters. No momento, eles podem apenas executar / obter conjuntos de campo, mas no futuro você pode ter uma lógica de validação ou dependências entre propriedades que precisam ser testadas. É mais fácil escrevê-lo agora enquanto você pensa sobre isso, lembrando-se de adaptá-lo se chegar a hora.
fonte
em geral, quando um método é definido apenas para determinados valores, teste valores dentro e além da borda do que é aceitável. Em outras palavras, verifique se o seu método faz o que deveria fazer, mas nada mais . Isso é importante, porque quando você falhar, você quer falhar mais cedo.
Nas hierarquias de herança, certifique-se de testar a conformidade com LSP .
Testar getters e setters padrão não me parece muito útil, a menos que você esteja planejando validar mais tarde.
fonte
bem, se você acha que pode quebrar, escreva um teste. Normalmente eu não testei o setter / getter, mas vamos dizer que você cria um para User.Name, que concatena o nome e o sobrenome, eu escreveria um teste para que, se alguém alterar a ordem do sobrenome e do nome, pelo menos ele saberia ele mudou algo que foi testado.
fonte
A resposta canônica é "teste qualquer coisa que possa quebrar". Se você tiver certeza de que as propriedades não quebrarão, não as teste.
E uma vez que algo foi quebrado (você encontra um bug), obviamente significa que você precisa testá-lo. Escreva um teste para reproduzir o erro, observe-o falhar, corrija-o e depois passe no teste.
fonte
Como eu entendo os testes de unidade no contexto do desenvolvimento ágil, Mike, sim, você precisa testar os getters e setters (supondo que eles sejam visíveis publicamente). Todo o conceito de teste de unidade é testar a unidade de software, que é uma classe nesse caso, como uma caixa preta . Como os getters e setters são visíveis externamente, é necessário testá-los junto com Authenticate and Save.
fonte
Se os métodos Autenticar e Salvar usarem as propriedades, seus testes tocarão indiretamente nas propriedades. Desde que as propriedades estejam apenas fornecendo acesso aos dados, o teste explícito não deve ser necessário (a menos que você esteja buscando 100% de cobertura).
fonte
Eu testaria seus getters e setters. Dependendo de quem está escrevendo o código, algumas pessoas alteram o significado dos métodos getter / setter. Eu vi a inicialização variável e outra validação como parte dos métodos getter. Para testar esse tipo de coisa, você deseja testes de unidade que cubram esse código explicitamente.
fonte
Pessoalmente, eu "testaria qualquer coisa que possa quebrar" e o getter simples (ou propriedades automáticas ainda melhores) não quebrará. Eu nunca tive uma declaração de retorno simples falhar e, portanto, nunca tenho teste para eles. Se os getters tiverem cálculos dentro deles ou alguma outra forma de declaração, eu certamente adicionaria testes para eles.
Pessoalmente, uso o Moq como uma estrutura de objeto simulada e, em seguida, verifico se meu objeto chama os objetos circundantes da maneira que deveria.
fonte
Você deve cobrir a execução de todos os métodos da classe com UT e verificar o valor de retorno do método. Isso inclui getters e setters, especialmente no caso de os membros (propriedades) serem classes complexas, o que requer grande alocação de memória durante sua inicialização. Ligue para o setter com uma string muito grande, por exemplo (ou algo com símbolos gregos) e verifique se o resultado está correto (não truncado, a codificação é boa etc.)
No caso de números inteiros simples, isso também se aplica - o que acontece se você passar muito tempo em vez de inteiro? Essa é a razão pela qual você escreve UT :)
fonte
Eu não testaria a configuração real das propriedades. Eu ficaria mais preocupado com o modo como essas propriedades são preenchidas pelo consumidor e com o que elas as preenchem. Em qualquer teste, você deve avaliar os riscos com o tempo / custo do teste.
fonte
Você deve testar "todo bloco de código não trivial" usando testes de unidade na medida do possível.
Se suas propriedades são triviais e é improvável que alguém apresente um bug, deve ser seguro não testá-las.
Seus métodos Authenticate () e Save () parecem bons candidatos para teste.
fonte
Idealmente, você teria feito seus testes de unidade enquanto escrevia a classe. É assim que você deve fazer isso ao usar o Test Driven Development. Você adiciona os testes à medida que implementa cada ponto de função, certificando-se de cobrir também os casos extremos.
Escrever os testes depois é muito mais doloroso, mas factível.
Aqui está o que eu faria na sua posição:
Isso deve fornecer um bom conjunto de testes de unidade que funcionarão como um bom buffer contra regressões.
O único problema com essa abordagem é que o código precisa ser projetado para ser testável dessa maneira. Se você cometeu algum erro de acoplamento desde o início, não poderá obter alta cobertura com muita facilidade.
É por isso que é realmente importante escrever os testes antes de escrever o código. Obriga você a escrever um código que seja fracamente acoplado.
fonte
Não teste obviamente o código de funcionamento (padrão). Portanto, se seus setters e getters são apenas "propertyvalue = value" e "return propertyvalue", não faz sentido testá-lo.
fonte
Mesmo get / set pode ter conseqüências estranhas, dependendo de como elas foram implementadas, portanto devem ser tratadas como métodos.
Cada teste destes precisará especificar conjuntos de parâmetros para as propriedades, definindo propriedades aceitáveis e inaceitáveis para garantir que as chamadas retornem / falhem da maneira esperada.
Você também precisa estar ciente das dicas de segurança, como um exemplo de injeção SQL, e testá-las.
Então, sim, você precisa se preocupar em testar as propriedades.
fonte
Eu acredito que é bobagem testar getters e setters quando eles fazem apenas uma operação simples. Pessoalmente, não escrevo testes de unidade complexos para cobrir qualquer padrão de uso. Eu tento escrever testes suficientes para garantir que eu lidei com o comportamento normal de execução e com o máximo de casos de erro que consigo imaginar. Escreverei mais testes de unidade como resposta a relatórios de erros. Uso o teste de unidade para garantir que o código atenda aos requisitos e para facilitar futuras modificações. Sinto-me muito mais disposto a alterar o código quando sei que, se eu quebrar algo, um teste falhará.
fonte
Eu escreveria um teste para qualquer coisa para a qual você esteja escrevendo um código que possa ser testado fora da interface GUI.
Normalmente, qualquer lógica que escrevo que tenha qualquer lógica de negócios que eu coloque dentro de outra camada ou camada de lógica de negócios.
Em seguida, escrever testes para qualquer coisa que faça algo é fácil de fazer.
Primeiro passe, escreva um teste de unidade para cada método público em sua "Camada lógica de negócios".
Se eu tivesse uma aula como esta:
A primeira coisa que eu faria antes de escrever qualquer código sabendo que eu tinha essas ações para executar seria começar a escrever testes de unidade.
Escreva seus testes para validar o código que você escreveu para fazer alguma coisa. Se você iterar sobre uma coleção de coisas e alterar algo sobre cada uma delas, escreva um teste que faça a mesma coisa e afirme o que realmente aconteceu.
Há muitas outras abordagens que você pode adotar, como o Behavoir Driven Development (BDD), que é mais envolvido e não é um ótimo lugar para começar com suas habilidades de teste de unidade.
Portanto, a moral da história é: teste qualquer coisa que faça qualquer coisa com a qual você possa estar preocupado; mantenha os testes de unidade testando coisas específicas de tamanho pequeno; muitos testes são bons.
Mantenha sua lógica de negócios fora da camada da interface do usuário para que você possa escrever facilmente testes para eles e será bom.
Eu recomendo o TestDriven.Net ou ReSharper, pois ambos se integram facilmente ao Visual Studio.
fonte
Eu recomendaria escrever vários testes para os métodos Authenticate e Save. Além do caso de sucesso (onde todos os parâmetros são fornecidos, tudo está escrito corretamente, etc.), é bom ter testes para vários casos de falha (parâmetros incorretos ou ausentes, conexões indisponíveis do banco de dados, se aplicável, etc). Eu recomendo o Teste de unidade pragmática em C # com o NUnit como referência.
Como outros já declararam, os testes de unidade para getters e setters são um exagero, a menos que exista lógica condicional em seus getters e setters.
fonte
Embora seja possível adivinhar corretamente onde seu código precisa ser testado, geralmente acho que você precisa de métricas para fazer backup dessa suposição. Na minha opinião, o teste de unidade anda de mãos dadas com as métricas de cobertura de código.
Codifique com muitos testes, mas uma pequena cobertura não foi bem testada. Dito isto, o código com 100% de cobertura, mas não testando os casos de limite e erro, também não é ótimo.
Você deseja um equilíbrio entre alta cobertura (mínimo de 90%) e dados de entrada variáveis.
Lembre-se de testar "lixo"!
Além disso, um teste de unidade não é um teste de unidade, a menos que verifique uma falha. Os testes de unidade que não possuem afirmações ou estão marcados com exceções conhecidas simplesmente testam que o código não morre quando é executado!
Você precisa projetar seus testes para que eles sempre relatem falhas ou dados inesperados / indesejados!
fonte
Torna o nosso código melhor ... ponto final!
Uma coisa que nós, desenvolvedores de software, esquecemos ao fazer o desenvolvimento orientado a testes é o objetivo por trás de nossas ações. Se um teste de unidade estiver sendo gravado depois que o código de produção já estiver em vigor, o valor do teste será muito baixo (mas não será completamente perdido).
No verdadeiro espírito do teste de unidade, esses testes não existem principalmente para "testar" mais do nosso código; ou para obter uma cobertura de código 90% a 100% melhor. Esses são todos os benefícios adicionais de escrever os testes primeiro. A grande recompensa é que nosso código de produção acaba sendo gravado muito melhor devido ao processo natural do TDD.
Para ajudar a comunicar melhor essa idéia, o seguinte pode ser útil na leitura:
A teoria falha de testes de unidade
Desenvolvimento de software proposital
Se acharmos que o ato de escrever mais testes de unidade é o que nos ajuda a obter um produto de maior qualidade, podemos estar sofrendo de um culto à carga de desenvolvimento orientado a testes.
fonte