Por que Mockito não zomba de métodos estáticos?


267

Li alguns tópicos aqui sobre métodos estáticos e acho que entendo os problemas que o uso indevido / uso excessivo de métodos estáticos pode causar. Mas eu realmente não entendi por que é difícil zombar de métodos estáticos.

Sei que outras estruturas de simulação, como o PowerMock, podem fazer isso, mas por que o Mockito não pode?

Eu li este artigo , mas o autor parece ser religiosamente contra a palavra static, talvez seja meu entendimento fraco.

Uma explicação / link fácil seria ótimo.


12
Apenas uma observação: o PowerMock não é uma biblioteca de objetos simulada em si, apenas adiciona esses recursos (simulando estática e ctors) sobre outras bibliotecas. Usamos o PowerMock + Mockito no trabalho, eles flutuam bem um com o outro.
Matthias

Respostas:


238

Acho que o motivo pode ser que as bibliotecas de objetos simulados normalmente criam zombarias criando classes dinamicamente em tempo de execução (usando cglib ). Isso significa que eles implementam uma interface em tempo de execução (é o que o EasyMock faz se não me engano) ou herdam da classe para zombar (é o que o Mockito faz se não me engano). Ambas as abordagens não funcionam para membros estáticos, pois você não pode substituí-los usando herança.

A única maneira de zombar de estática é modificar o código de byte de uma classe em tempo de execução, que eu suponho que seja um pouco mais envolvido do que herança.

Esse é o meu palpite, pelo que vale a pena ...


7
O mesmo vale para zombadores de construtores, a propósito. Também esses não podem ser alterados por herança.
Matthias

11
Também vale a pena acrescentar que alguns defensores de TDD / TBD percebem a falta de método estático e zombaria de construtores como uma coisa boa . Eles argumentam que, quando você tem que zombar de métodos ou construtores estáticos, isso é um indicador para um projeto de classe ruim. Por exemplo, ao seguir uma abordagem purista de IoC na montagem de seus módulos de código, você nunca terá a necessidade de zombar de estática ou de um médico (a menos que eles façam parte de algum componente da caixa preta, é claro). Veja também giorgiosironi.blogspot.com/2009/11/…
Matthias

200
Eu acho que as ferramentas de simulação devem fornecer o que você precisa sem assumir que elas sabem o que é melhor para você. Por exemplo, se eu estivesse usando uma biblioteca de terceiros que utilizasse uma chamada de método estática que eu precisava zombar, seria bom poder fazê-lo. A idéia de que uma estrutura simulada não fornecerá a você alguma capacidade porque é vista como um design ruim é fundamentalmente falha.
Lo-Tan

11
@ Lo-Tan - é como dizer que um idioma deve ser capaz de tudo, não assumindo que ele saiba melhor do que você. Isso é apenas vaidade da sua parte, porque parece imponente. O problema aqui é que a batalha "anti / pró-estática" não está clara, assim como os quadros. Concordo que deveríamos ter os dois. Mas onde os fatos são claros, prefiro uma estrutura que os imponha . Essa é uma maneira de aprender - ferramentas para mantê-lo no caminho certo. Então você mesmo não precisa. Mas agora toda cabeça de macarrão pode impor seu chamado "bom design". "Fundamentalmente falho" ...
nevvermind 25/11/14

13
@nevvermind Eh? Uma linguagem de alto nível visa ajudá-lo e ter as abstrações necessárias para que você possa se concentrar nas peças importantes. Uma biblioteca de testes é uma ferramenta - uma ferramenta que eu uso para produzir código de melhor qualidade e espero que seja melhor projetado. Qual é o sentido de uma biblioteca de teste / simulação quando ela tem limitações que podem significar que eu não posso usá-la quando estou tendo que integrar o código mal projetado de outra pessoa? Não parece bem pensado, ao passo que boas linguagens foram .
Lo-Tan

28

Se você precisar zombar de um método estático, é um forte indicador de um design ruim. Geralmente, você zomba da dependência de sua classe em teste. Se sua classe em teste refere-se a um método estático - como java.util.Math # sin, por exemplo - significa que a classe em teste precisa exatamente dessa implementação (de precisão versus velocidade, por exemplo). Se você deseja abstrair de uma implementação concreta do seio, provavelmente precisará de uma interface (você vê para onde isso vai dar)?


3
Bem, usei métodos estáticos para fornecer abstrações de alto nível, como uma "fachada de persistência estática". Essa fachada mantém o código do cliente longe das complexidades e dos detalhes de baixo nível de uma API ORM, fornecendo uma API mais consistente e fácil de usar, além de permitir muita flexibilidade.
Rogério

E por que você tem que zombar? Se você depende do método estático, sua "unidade" ou "módulo" não é apenas a classe, mas também inclui a "fachada de persistência estática".
Jan

88
É verdade, mas às vezes você pode não ter escolha se, por exemplo, precisar zombar de um método estático que esteja em alguma classe de terceiros.
Stijn Geukens

6
É verdade, mas às vezes podemos estar lidando com singletons.
Manu Manjunath

O único pensamento que não pode ser resolvido com a abstração é o excesso de níveis de abstração ... A adição de camadas de abstração aumenta a complexidade e geralmente é desnecessária. Penso nos exemplos que já vi de estruturas que tentam zombar de System.currentTimeMillis () envolvendo essa chamada simples em uma única classe. Acabamos com uma classe singleton por método, em vez de simplesmente ter métodos - apenas para facilitar o teste. E então quando você introduzir um dep 3-parte que chama o método estático dirigir em vez de através de seu invólucro de singleton, os testes falhar de qualquer maneira ...
Pe Jeremy Krieg

5

Eu realmente acho que é cheiro de código, se você precisar zombar de métodos estáticos também.

  • Métodos estáticos para acessar funcionalidades comuns? -> Use uma instância singleton e injete esse
  • Código de terceiros? -> Coloque-o em sua própria interface / delegado (e, se necessário, torne-o um singleton também)

A única vez que isso parece exagero para mim, são bibliotecas como o Goiaba, mas você não precisa zombar desse tipo porque faz parte da lógica ... (coisas como Iterables.transform (..))
Dessa forma, seu próprio código permanece limpo, você pode zombar de todas as suas dependências de maneira limpa e possui uma camada anticorrupção contra dependências externas. Eu já vi o PowerMock em prática e todas as classes para as quais precisávamos eram mal projetadas. Além disso, a integração do PowerMock às vezes causava sérios problemas
(por exemplo, https://code.google.com/p/powermock/issues/detail?id=355 )

PS: O mesmo vale para métodos privados também. Eu não acho que os testes devam saber sobre os detalhes dos métodos privados. Se uma classe é tão complexa que tenta zombar de métodos privados, provavelmente é um sinal para dividi-la ...


2
O Singleton fará com que você encontre todos os tipos de problemas, principalmente quando perceber que realmente precisa de mais de uma instância e agora precisará refatorar todo o sistema para que isso aconteça.
Ricardo Freitas

Eu não disse que recomendo o Padrão Singleton a todos. O que eu quis dizer é que, se eu tiver que decidir entre uma classe de utilitário estático e um Singleton oferecendo a mesma funcionalidade, eu escolheria o Singleton. E se uma classe é um Singleton ou não deve ser controlada pela estrutura DI de qualquer maneira, na minha classe I @Inject SomeDependencye na minha configuração eu defino bind(SomeDependency.class).in(Singleton.class). Assim, se amanhã não for mais um Singleton, eu altero a configuração e pronto.
Pete83

@ pete83 eu ouço você irmão. No entanto, tenho um problema com as bibliotecas de teste ou estruturas que exigem que os desenvolvedores alterem seu design para atender aos limites / design da estrutura de teste. Isso é o IMO colocando a carroça diante do cavalo ou a cauda abanando o cachorro.
Matt Campbell

1
Esse argumento faz pouco sentido para mim. Os padrões de Singleton caíram em desuso há anos, por muitas razões para listar aqui. O que constitui código "limpo"? Se eu tenho um método de instância de classe que chama um método auxiliar estático que retorna alguma operação de E / S, por que não gostaria que isso fosse ridicularizado em um teste? E como é esse design deficiente? Todos esses métodos estáticos de zombaria que envolvem a mão não se somam. Zombar de um método é o oposto de testá-lo. Se for muito difícil de implementar, basta dizer isso e terminar com isso
eggmatters

Oh cara, eu nunca estava falando sobre o padrão Singleton da velha escola, onde todo mundo chama por Foo.getInstance()toda parte. Acabei de escrever singleton na resposta para combater o argumento ", mas um método estático não requer a criação de muitos objetos wrapper". Também conceitualmente para mim, há pouca diferença entre um método estático e um método de instância em um singleton, apenas que você não pode zombar desse colaborador singleton. Mas singleton ou não não é absolutamente o ponto que eu estava tentando enfatizar, o objetivo é injetar e zombar de colaboradores e não chamar métodos estáticos se isso dificulta o teste.
pete83 10/01

4

Mockito retorna objetos, mas estático significa "nível de classe, não nível de objeto". Portanto, o mockito dará exceção de ponteiro nulo para estática.


0

Em alguns casos, pode ser difícil testar métodos estáticos, especialmente se eles precisam ser ridicularizados, e é por isso que a maioria das estruturas de simulação não os suporta. Achei esta postagem do blog muito útil para determinar como zombar de métodos e classes estáticos.


1
A zombaria de métodos estáticos é ainda mais fácil do que os métodos de zombaria de instâncias (já que não há instância), ao usar uma API de zombaria adequada.
Rogério

É como responder à pergunta com a própria pergunta, e é por isso que é difícil fazê-lo, para o que isso não é uma resposta.
Matthias

40
Fiz uma votação negativa porque a postagem do blog recomenda uma solução alternativa dispendiosa (refatoração do código de produção), em vez de realmente resolver o problema de isolar uma classe dos métodos estáticos que ela usa. IMO, uma ferramenta de zombaria que realmente faz o trabalho não discriminaria métodos de qualquer tipo; um desenvolvedor deve ter liberdade para decidir se o uso de métodos estáticos é bom ou ruim em uma determinada situação, em vez de ser forçado a seguir um caminho.
Rogério
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.