Eu descobri que existem apenas três maneiras de dependências de teste de unidade (mock / stub) que são estáticas no C # .NET:
Dado que dois deles não são gratuitos e um não atingiu a versão 1.0, zombar de coisas estáticas não é muito fácil.
Isso torna métodos estáticos e "mal" (no sentido de teste de unidade)? E se sim, por que o ressarpiador quer que eu faça algo que possa ser estático, estático? (Assumir que o re-compartilhador também não é "mau".)
Esclarecimento: Estou falando do cenário em que você deseja testar um método por unidade e esse método chama um método estático em uma unidade / classe diferente . Pela maioria das definições de teste de unidade, se você apenas permitir que o método em teste chame o método estático na outra unidade / classe, então você não é um teste de unidade, é um teste de integração . (Útil, mas não um teste de unidade.)
fonte
Respostas:
Olhando para as outras respostas aqui, acho que pode haver alguma confusão entre métodos estáticos que mantêm um estado estático ou causam efeitos colaterais (que me parecem uma péssima idéia) e métodos estáticos que apenas retornam um valor.
Os métodos estáticos que não mantêm nenhum estado e não causam efeitos colaterais devem ser facilmente testados por unidade. De fato, considero esses métodos uma forma de programação funcional "pobre"; você entrega ao método um objeto ou valor e ele retorna um objeto ou valor. Nada mais. Não vejo como esses métodos afetariam negativamente o teste de unidade.
fonte
Você parece estar confundindo dados estáticos e métodos estáticos . O novo compartilhador, se bem me lembro, recomenda tornar
private
estáticos os métodos dentro de uma classe, se puderem ser feitos - acredito que isso traga um pequeno benefício de desempenho. Não é recomendável fazer "qualquer coisa que possa ser" estática!Não há nada errado com os métodos estáticos e eles são fáceis de testar (desde que não alterem nenhum dado estático). Por exemplo, pense em uma biblioteca de matemática, que é uma boa candidata a uma classe estática com métodos estáticos. Se você possui um método (artificial) como este:
então isso é eminentemente testável e não tem efeitos colaterais. Você apenas verifica que, quando passa, digamos, 20, recebe 400. Não há problema.
fonte
System.Math
) para não mencionar a abundância de métodos estáticos de fábrica etc. Além disso, você nunca seria capaz de usar nenhum método de extensão etc. O fato é que funções simples como esta são fundamental para as línguas modernas. Você pode testá-los isoladamente (já que geralmente serão determinísticos) e depois usá-los em suas aulas sem se preocupar. Não é um problema!Se a pergunta real aqui for "Como faço para testar este código?":
Em seguida, basta refatorar o código e injetar como de costume a chamada para a classe estática assim:
fonte
A estática não é necessariamente ruim, mas pode limitar suas opções quando se trata de teste de unidade com falsificações / zombarias / tocos.
Existem duas abordagens gerais para zombar.
O primeiro (tradicional - implementado pela RhinoMocks, Moq, NMock2; zombarias e tocos manuais também estão neste campo) se baseia em costuras de teste e injeção de dependência. Suponha que você esteja testando um código estático e que tenha dependências. O que acontece frequentemente no código projetado dessa maneira é que a estática cria suas próprias dependências, invertendo a inversão de dependência . Você logo descobre que não pode injetar interfaces simuladas no código em teste projetado dessa maneira.
O segundo (simulado qualquer coisa - implementado por TypeMock, JustMock e Moles) depende da API de criação de perfil do .NET . Ele pode interceptar qualquer uma das instruções do CIL e substituir um pedaço do seu código por um falso. Isso permite que o TypeMock e outros produtos deste campo zombem de qualquer coisa: estática, classes seladas, métodos particulares - coisas que não foram projetadas para serem testáveis.
Há um debate em andamento entre duas escolas de pensamento. Diz-se, siga os princípios e o design do SOLID para testabilidade (que geralmente inclui a facilidade na estática). O outro diz: compre TypeMock e não se preocupe.
fonte
Verifique isto: "Métodos estáticos são morte para testabilidade" . Breve resumo do argumento:
Para testar a unidade, você precisa pegar um pequeno pedaço do seu código, reconectar suas dependências e testá-lo isoladamente. Isso é difícil com métodos estáticos, não apenas no caso de eles acessarem o estado global, mas mesmo se apenas chamarem outros métodos estáticos.
fonte
A verdade simples raramente reconhecida é que, se uma classe contiver uma dependência visível do compilador em outra classe, ela não poderá ser testada isoladamente dessa classe. Você pode falsificar algo que parece um teste e aparecerá em um relatório como se fosse um teste.
Mas não terá as principais propriedades definidoras de um teste; falhando quando as coisas estão erradas, passando quando estão certas.
Isso se aplica a quaisquer chamadas estáticas, chamadas de construtor e qualquer referência a métodos ou campos não herdados de uma classe ou interface base . Se o nome da classe aparecer no código, é uma dependência visível do compilador e você não pode testar validamente sem ela. Qualquer pedaço menor simplesmente não é uma unidade testável válida . Qualquer tentativa de tratá-lo como se fosse, terá resultados não mais significativos do que escrever um pequeno utilitário para emitir o XML usado por sua estrutura de teste para dizer 'teste aprovado'.
Dado isso, existem três opções:
defina o teste de unidade como sendo o teste da unidade composta por uma classe e suas dependências codificadas. Isso funciona, desde que você evite dependências circulares.
nunca crie dependências em tempo de compilação entre as classes que você é responsável por testar. Isso funciona, desde que você não se importe com o estilo de código resultante.
não teste de unidade, teste de integração. O que funciona, desde que não entre em conflito com outra coisa para a qual você precisa usar o termo teste de integração.
fonte
Math.Pi
em um método não o torna um teste de integração por nenhuma definição razoável.Não há duas maneiras sobre isso. As sugestões do ReSharper e vários recursos úteis do C # não seriam usados com tanta frequência se você estivesse escrevendo testes de unidade atômica isolados para todo o seu código.
Por exemplo, se você tem um método estático e precisa removê-lo, não pode, a menos que use uma estrutura de isolamento baseada em perfil. Uma solução compatível com chamada é alterar a parte superior do método para usar a notação lambda. Por exemplo:
ANTES:
DEPOIS DE:
Os dois são compatíveis com chamadas. Os chamadores não precisam mudar. O corpo da função permanece o mesmo.
Em seguida, em seu código de teste de unidade, você pode stubar esta chamada da seguinte maneira (supondo que ela esteja em uma classe chamada Database):
Tome cuidado para substituí-lo pelo valor original após concluir. Você pode fazer isso através de uma tentativa / finalmente ou, na limpeza do teste de unidade, a chamada após cada teste, escreva um código como este:
que reinvocará o inicializador estático da sua classe.
Os Funda Lambda não são tão ricos em suporte quanto os métodos estáticos regulares, portanto, essa abordagem tem os seguintes efeitos colaterais indesejáveis:
Mas digamos que você evite completamente a estática e a converta em um método de instância. Ainda não é ridículo, a menos que o método seja virtual ou implementado como parte de uma interface.
Portanto, na realidade, qualquer pessoa que sugerir o remédio para stubbing métodos estáticos deve torná-los métodos de instância, eles também estariam contra métodos de instância que não são virtuais ou fazem parte de uma interface.
Então, por que o C # tem métodos estáticos? Por que ele permite métodos de instância não virtuais?
Se você usar um desses "Recursos", simplesmente não poderá criar métodos isolados.
Então, quando você os usa?
Use-os para qualquer código que você não espere que alguém queira apagar. Alguns exemplos: o método Format () da classe String, o método WriteLine () da classe Console, o método Cosh () da classe Math
E mais uma coisa. A maioria das pessoas não liga para isso, mas se você puder sobre o desempenho de uma chamada indireta, esse é outro motivo para evitar métodos de instância. Há casos em que é um sucesso de desempenho. É por isso que existem métodos não virtuais em primeiro lugar.
fonte
O R # não é a única ferramenta que fará essa sugestão. A análise de código FxCop / MS também fará o mesmo.
Eu diria que, se o método é estático, geralmente deve ser testável como também. Isso traz alguma consideração de design e provavelmente mais discussão do que eu tenho agora, aguardando pacientemente os votos negativos e comentários ...;)
fonte
Vejo que, depois de muito tempo, ninguém declarou um fato realmente simples. Se o re-afiador me disser que eu posso tornar um método estático, isso significa uma coisa enorme para mim, ouço a voz dele me dizer: "ei, você, essas peças de lógica não são a RESPONSABILIDADE da classe atual de lidar, por isso deve ficar de fora em alguma classe auxiliar ou algo assim ".
fonte
Se o método estático for chamado de dentro de outro método , não será possível impedir ou substituir essa chamada. Isso significa que esses dois métodos formam uma única unidade; Teste de unidade de qualquer tipo testa os dois.
E se esse método estático fala com a Internet, conecta bancos de dados, mostra pop-ups da GUI ou converte o teste de unidade em uma bagunça completa, ele simplesmente funciona sem nenhum trabalho fácil. Um método que chama esse método estático não pode ser testado sem a refatoração, mesmo que tenha muito código puramente computacional que se beneficiaria muito com o teste de unidade.
fonte
Acredito que o Resharper esteja fornecendo orientações e aplique as diretrizes de codificação com as quais foi configurado. Quando eu uso o Resharper e ele me diz que um método deve ser estático, ele deve estar em um método privado que não atua em nenhuma variável de instância.
Agora, quanto à testabilidade, esse cenário não deve ser um problema, pois você também não deve testar métodos privados.
Quanto à testabilidade de métodos estáticos que são públicos, o teste de unidade fica difícil quando métodos estáticos tocam no estado estático. Pessoalmente, eu manteria isso no mínimo e usaria métodos estáticos como funções puras, tanto quanto possível, onde quaisquer dependências são passadas para o método que podem ser controladas através de um dispositivo de teste. No entanto, esta é uma decisão de design.
fonte