Eu tenho uma aula final, algo como isto:
public final class RainOnTrees{
public void startRain(){
// some code here
}
}
Estou usando esta classe em alguma outra classe como esta:
public class Seasons{
RainOnTrees rain = new RainOnTrees();
public void findSeasonAndRain(){
rain.startRain();
}
}
e na minha classe de teste JUnit, Seasons.java
quero zombar da RainOnTrees
classe. Como posso fazer isso com o Mockito?
Respostas:
A zombaria de classes / métodos estáticos / finais é possível apenas com o Mockito v2.
adicione isso no seu arquivo gradle:
Isso não é possível com o Mockito v1, nas Perguntas frequentes do Mockito :
fonte
O Mockito 2 agora suporta classes e métodos finais !
Mas, por enquanto, esse é um recurso de "incubação". Requer algumas etapas para ativá-lo, descritas em O que há de novo no Mockito 2 :
fonte
org.mockito.plugins.MockMaker
arquivo na pasta correta.Você não pode zombar de uma aula final com o Mockito, pois não pode fazê-lo sozinho.
O que faço é criar uma classe não final para encerrar a classe final e usá-la como delegada. Um exemplo disso é a
TwitterFactory
classe, e esta é a minha classe ridicularizável:A desvantagem é que há muito código padrão; a vantagem é que você pode adicionar alguns métodos que podem estar relacionados aos negócios de aplicativos (como o getInstance que está recebendo um usuário em vez de um accessToken, no caso acima).
No seu caso, eu criaria uma
RainOnTrees
classe não final que delega para a classe final. Ou, se você puder torná-lo não final, seria melhor.fonte
@Delegate
para lidar com grande parte do clichê.adicione isso no seu arquivo gradle:
esta é uma configuração para fazer o mockito funcionar com as classes finais
fonte
org.mockito.exceptions.base.MockitoInitializationException: Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
Use Powermock. Este link mostra como fazê-lo: https://github.com/jayway/powermock/wiki/MockFinal
fonte
Powermock
para zombar das classes finais e dos métodos estáticos para aumentar minha cobertura oficialmente verificadaSonarqube
. A cobertura foi de 0% desde o SonarQube, por qualquer motivo, não reconhece as classes que usam o Powermock em qualquer lugar dentro dele. Levei um tempo para mim e minha equipe para perceber isso a partir de algum tópico online. Portanto, esse é apenas um dos motivos para ter cuidado com o Powermock e provavelmente não o usar.Apenas para acompanhar. Adicione esta linha ao seu arquivo gradle:
Eu tentei várias versões do mockito-core e mockito-all. Nenhum deles funciona.
fonte
Eu acho que você fez isso
final
porque deseja impedir que outras classes se estendamRainOnTrees
. Como o Java efetivo sugere (item 15), há outra maneira de manter uma classe próxima da extensão sem torná-lafinal
:Remova a
final
palavra - chave;Faça o seu construtor
private
. Nenhuma classe poderá estendê-lo porque não poderá chamar osuper
construtor;Crie um método de fábrica estático para instanciar sua classe.
Usando essa estratégia, você poderá usar o Mockito e manter sua classe fechada para extensão com pouco código padrão.
fonte
Eu tive o mesmo problema. Como a classe que eu estava tentando zombar era uma classe simples, simplesmente criei uma instância e a devolvi.
fonte
Faça uma tentativa:
Funcionou para mim. "SomeMockableType.class" é a classe pai do que você deseja zombar ou espionar, e someInstanceThatIsNotMockableOrSpyable é a classe real que você deseja zombar ou espionar.
Para mais detalhes, dê uma olhada aqui
fonte
Outra solução alternativa, que pode ser aplicada em alguns casos, é criar uma interface implementada por essa classe final, alterar o código para usar a interface em vez da classe concreta e zombar da interface. Isso permite separar o contrato (interface) da implementação (classe final). Obviamente, se o que você deseja é realmente vincular-se à classe final, isso não se aplicará.
fonte
Na verdade, há uma maneira que eu uso para espionagem. Funcionaria para você apenas se duas condições prévias fossem atendidas:
Lembre-se do Item 16 do Effective Java . Você pode criar um wrapper (não final) e encaminhar todas as chamadas para a instância da classe final:
Agora você não apenas pode zombar de sua classe final, mas também espioná-la:
fonte
No Mockito 3 e mais, tenho o mesmo problema e o corrigi a partir deste link
Zombe de classes e métodos finais com o Mockito, conforme a seguir
fonte
Economia de tempo para pessoas que enfrentam o mesmo problema (Mockito + Final Class) no Android + Kotlin. Como no Kotlin, as aulas são finais por padrão. Encontrei uma solução em um dos exemplos do Google Android com o componente Arquitetura. Solução escolhida aqui: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample
Crie as seguintes anotações:
Modifique seu arquivo gradle. Veja o exemplo aqui: https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/build.gradle
Agora você pode anotar qualquer classe para torná-la aberta para teste:
fonte
Isso pode ser feito se você estiver usando o Mockito2, com o novo recurso de incubação que suporta a zombaria das classes e métodos finais.
Pontos principais a serem observados:
1. Crie um arquivo simples com o nome “org.mockito.plugins.MockMaker” e coloque-o em uma pasta chamada “mockito-extensions”. Essa pasta deve ser disponibilizada no caminho de classe.
2. O conteúdo do arquivo criado acima deve ser uma única linha, conforme indicado abaixo:
mock-maker-inline
As duas etapas acima são necessárias para ativar o mecanismo de extensão mockito e usar esse recurso de aceitação.
As classes de amostra são as seguintes: -
FinalClass.java
}
Foo.java
}
FooTest.java
}
Espero que ajude.
Artigo completo presente aqui, zombando do imbatível .
fonte
Sim, mesmo problema aqui, não podemos zombar de uma aula final com o Mockito. Para ser exato, o Mockito não pode zombar / espionar o seguinte:
Mas usar uma classe de invólucro me parece um preço muito alto a pagar; portanto, obtenha o PowerMockito.
fonte
Eu acho que você precisa pensar mais em princípio. Em vez disso, a classe final usa a interface dele e a interface simulada.
Por esta:
adicionar
e zombe da sua interface:
fonte
Por favor, olhe para o JMockit . Possui extensa documentação com muitos exemplos. Aqui você tem um exemplo de solução do seu problema (para simplificar, eu adicionei o construtor
Seasons
para injetar umaRainOnTrees
instância simulada ):fonte
Soluções fornecidas por RC e Luigi R. Viggiano juntas são possivelmente a melhor idéia.
Embora Mockito não possa , por design, zombar das classes finais, a abordagem de delegação é possível . Isso tem suas vantagens:
No seu caso de teste, você encaminha deliberadamente as chamadas para o sistema em teste. Por isso, por design, sua decoração não faz nada.
Portanto, o teste também pode demonstrar que o usuário pode decorar a API apenas em vez de estendê-la.
Em uma nota mais subjetiva: prefiro manter as estruturas no mínimo, e é por isso que JUnit e Mockito geralmente são suficientes para mim. De fato, restringir esse caminho às vezes me obriga a refatorar o bem também.
fonte
Se você está tentando executar o teste de unidade na pasta de teste , a solução principal está correta. Basta seguir adicionando uma extensão.
Mas se você deseja executá-lo com a classe relacionada ao Android, como contexto ou atividade, que está na pasta androidtest , a resposta é para você.
fonte
Adicione estas dependências para executar mockito com sucesso:
testImplementation 'org.mockito: mockito-core: 2.24.5'
testImplementation "org.mockito: mockito-inline: 2.24.5"
fonte
Como outros já declararam, isso não funcionará imediatamente com o Mockito. Eu sugeriria o uso de reflexão para definir os campos específicos no objeto que está sendo usado pelo código em teste. Se você se encontra fazendo muito isso, pode agrupar essa funcionalidade em uma biblioteca.
Como um aparte, se você é o único que marca as aulas como final, pare de fazer isso. Eu me deparei com essa pergunta porque estou trabalhando com uma API em que tudo foi marcado como final para evitar minha necessidade legítima de extensão (zombaria), e gostaria que o desenvolvedor não assumisse que nunca precisaria estender a classe.
fonte
final
deve ser o padrão.Para nós, foi porque excluímos o mockito-inline do koin-test. Um módulo gradle realmente precisava disso e, por motivo, apenas falhou nas compilações de versão (compilações de depuração no IDE funcionaram) :-P
fonte
Para a aula final, adicione abaixo a simulação e chame estática ou não estática.
1- adicione isso no nível da classe @SuppressStatucInitializationFor (value = {nome da classe com pacote})
2- PowerMockito.mockStatic (classname.class) zombará da classe
3- e use sua instrução when para retornar o objeto mock ao chamar o método desta classe.
Aproveitar
fonte
Não tentei final, mas para privado, usando a reflexão remova o modificador trabalhado! ter verificado mais, não funciona para final.
fonte