Eu realmente me apaixonei por testes de unidade e TDD - estou infectado por testes.
No entanto, o teste de unidade é normalmente usado para métodos públicos. Às vezes, também tenho que testar algumas suposições em métodos particulares, porque algumas são "perigosas" e a refatoração não pode ajudar mais. (Eu sei, estruturas de teste permitem testar métodos privados).
Portanto, tornou-se um hábito meu que a primeira e a última linha de um método privado sejam ambas afirmações.
No entanto, notei que tenho tendência a usar asserções em métodos públicos (assim como privados) apenas "para ter certeza". Poderia ser "duplicação de teste", uma vez que as suposições de método público são testadas externamente pela estrutura de teste de unidade?
Alguém poderia pensar em muitas afirmações como um cheiro de código?
fonte
Respostas:
Essas afirmações são realmente úteis para testar suas suposições, mas também servem a outro propósito realmente importante: documentação. Qualquer leitor de um método público pode ler as declarações para determinar rapidamente as condições pré e pós, sem precisar olhar para a suíte de testes. Por esse motivo, recomendo que você mantenha essas declarações por motivos de documentação, em vez de por motivos de teste. Tecnicamente, você está duplicando as asserções, mas elas servem a dois propósitos diferentes e são muito úteis em ambos.
Mantê-los como afirmações é melhor do que simplesmente usar comentários, porque eles verificam ativamente as premissas sempre que são executadas.
fonte
Parece que você está tentando fazer um projeto por contrato manualmente.
Fazer DbC é uma boa ideia, mas você deve pelo menos considerar mudar para um idioma que o suporte nativamente (como Eiffel ) ou pelo menos usar uma estrutura de contrato para sua plataforma (por exemplo, Microsoft Code Contracts for .NETé bem legal, sem dúvida a estrutura de contrato mais sofisticada do mercado, ainda mais poderosa que Eiffel). Dessa forma, você pode aproveitar melhor o poder dos contratos. Por exemplo, usando uma estrutura existente, você pode apresentar os contratos em sua documentação ou em um IDE (por exemplo, o Code Contracts for .NET é mostrado no IntelliSense e, se você tiver o VS Ultimate, pode até ser verificado estaticamente por um provador de teoremas automático em tempo de compilação enquanto você digita; da mesma forma, muitas estruturas de contrato Java possuem doclets JavaDoc que extraem automaticamente os contratos na documentação da API JavaDoc).
E mesmo que, na sua situação, não haja alternativa a fazê-lo manualmente, agora você pelo menos sabe como é chamado e pode ler sobre isso.
Então, resumindo: se você está realmente fazendo DbC, mesmo que não o conheça, essas afirmações são perfeitamente boas.
fonte
Sempre que você não tem controle total sobre seus parâmetros de entrada, é uma boa idéia testar antecipadamente se há erros simples. Falha no nulo, por exemplo.
Isso não é duplicação de seus testes, pois eles devem testar se o código falhou adequadamente, devido a parâmetros de entrada incorretos, e depois documentar isso .
Não acho que você deva afirmar os parâmetros de retorno (a menos que você tenha explicitamente um invariável que deseja que o leitor entenda). Este também é o trabalho dos unittests.
Pessoalmente, não gosto da
assert
declaração em Java, pois elas podem ser desativadas e, em seguida, é uma segurança falsa.fonte
Eu acho que o uso de asserções em métodos públicos é ainda mais importante, pois você não controla as entradas e pode ser mais provável que uma suposição seja quebrada.
O teste das condições de entrada deve ser realizado em todos os métodos públicos e protegidos. Se as entradas forem passadas diretamente para um método privado, o teste de suas entradas poderá ser redundante.
O teste das condições de saída (por exemplo, estado do objeto ou que retornam valor! = Null) deve ser realizado nos métodos internos (por exemplo, métodos privados). Se as saídas forem passadas diretamente de um método privado para a saída de um método público sem cálculos adicionais ou alterações de estado interno, o teste das condições de saída do método público poderá ser redundante.
Concordo com Oleksi, no entanto, que a redundância pode aumentar a legibilidade e também a manutenção (se a atribuição direta ou o retorno não for mais o caso no futuro).
fonte
É difícil ser independente de idioma sobre esse problema, pois os detalhes de como as asserções e o tratamento "adequado" de erros / exceções são implementados têm influência na resposta. Aqui está o meu $ 0,02, com base no meu conhecimento de Java e C ++.
Afirmar métodos privados é uma coisa boa, desde que você não exagere e os coloque em todos os lugares . Se você está aplicando métodos realmente simples ou verificando repetidamente coisas como campos imutáveis, está desorganizando o código desnecessariamente.
Geralmente, é melhor evitar afirmações em métodos públicos. Você ainda deve fazer coisas como verificar se o contrato do método não foi violado, mas, se for, você deve lançar exceções de tipo adequado com mensagens significativas, reverter o estado sempre que possível, etc. (o que @rwong chama de "completo tratamento adequado de manipulação de erros ").
De um modo geral, você só deve usar asserções para ajudar no seu desenvolvimento / depuração. Você não pode presumir que quem usa sua API terá afirmações ativadas quando usar seu código. Embora eles tenham alguma utilidade para ajudar a documentar o código, geralmente existem maneiras melhores de documentar as mesmas coisas (por exemplo, documentação do método, exceções).
fonte
Acrescentando à lista de respostas (principalmente) excepcionais, outro motivo para muitas afirmações e duplicação, é que você não sabe como, quando ou por quem a classe será modificada ao longo da vida. Se você estiver escrevendo um código de descarte que estará morto em um ano, não é uma preocupação. Se você estiver escrevendo um código que será usado em mais de 20 anos, ele parecerá bem diferente - e uma suposição que você tenha feito pode não ser mais válida. O cara que faz essa alteração agradece pelas declarações.
Além disso, nem todos os programadores são perfeitos - novamente, as afirmações significam que um desses "deslizes" não será propagado muito longe.
Não subestime o efeito que essas afirmações (e outras verificações sobre premissas) terão na redução do custo de manutenção.
fonte
Ter afirmações duplicadas não é errado por si só, mas as afirmações "apenas para garantir" não são as melhores. Realmente se resume ao que exatamente cada teste está tentando realizar. Afirme apenas o que é absolutamente necessário. Se um teste usa o Moq para verificar se um método é chamado, não importa realmente o que acontece depois que o método é chamado, o teste se preocupa apenas em garantir que o método seja chamado.
Se todos os testes unitários tiverem o mesmo conjunto de afirmações, exceto um ou dois, quando você refatorar um pouco, todos os testes poderão falhar pelo mesmo motivo, em vez de mostrar o verdadeiro impacto do refator. Você pode acabar em uma situação em que executa todos os testes, todos eles falham porque cada teste tem as mesmas afirmações, você corrige essa falha, executa os testes novamente, eles falham por outro motivo, você corrige essa falha. Repita até terminar.
Considere também a manutenção do seu projeto de teste. O que acontece quando você adiciona um novo parâmetro ou a saída é ajustada de vez em quando? Você precisaria voltar a vários testes e alterar uma declaração ou adicionar uma declaração? E, dependendo do seu código, você pode ter que configurar muito mais apenas para garantir que todas as declarações sejam aprovadas.
Eu posso entender o fascínio de querer incluir afirmações duplicadas no teste de unidade, mas é realmente um exagero. Eu segui o mesmo caminho com meu primeiro projeto de teste. Eu me afastei porque a manutenção sozinha estava me deixando louco.
fonte
Se sua estrutura de teste permitir acessadores, os métodos particulares de teste de unidade também serão uma boa ideia (IMO).
Eu faço. As asserções são válidas, mas seu primeiro objetivo deve ser fazer com que o cenário nem seja possível ; não apenas isso não acontece.
fonte
É uma prática ruim.
Você não deve testar métodos públicos / privados. Você deve testar a classe como um todo. Apenas verifique se você tem uma boa cobertura.
Se você seguir a maneira (primitiva) de testar cada método separadamente como regra geral, será extremamente difícil refatorar sua classe no futuro. E essa é uma das melhores coisas que o TDD permite que você faça.
Além disso, é duplicação. Além disso, sugere que o autor do código realmente não sabia o que estava fazendo. E o engraçado é que você faz .
Algumas pessoas tratam seus testes com menos cuidado do que seu código de produção. Eles não deveriam. Se alguma coisa, minha experiência sugere tratar os testes com mais cuidado. Eles valem a pena.
fonte