mocking private static
Aprenda métodos de simulação privada, estática e de vazio no Mockito com exemplos:
Nesta série de práticas Tutoriais no Mockito , demos uma olhada no diferentes tipos de Mockito Matchers no último tutorial.
De um modo geral, os métodos privados e estáticos de zombaria entram na categoria de zombaria incomum.
Se surgir a necessidade de simular métodos / classes privados e estáticos, isso indica código mal refatorado e não é realmente um código testável e é mais provável que algum código legado que não costumava ser muito amigável para testes de unidade.
Dito isso, ainda existe suporte para simulação de métodos privados e estáticos por alguns frameworks de teste de unidade como PowerMockito (e não diretamente pelo Mockito).
Métodos “nulos” de zombaria são comuns, pois pode haver métodos que essencialmente não retornam nada, como atualizar uma linha do banco de dados (considere isso como uma operação PUT de um endpoint da API Rest que aceita uma entrada e não retorna nenhuma saída).
O Mockito fornece suporte completo para métodos de simulação de void, que veremos com exemplos neste artigo.
como abrir extensão de arquivo json
O que você aprenderá:
- Powermock - Uma breve introdução
- Zombar de métodos privados
- Zombar de métodos estáticos
- Zombando de métodos de vazio
- dicas e truques
- Conclusão
- Leitura recomendada
Powermock - Uma breve introdução
Para o Mockito, não há suporte direto para simular métodos privados e estáticos. Para testar métodos privados, você precisará refatorar o código para alterar o acesso para protected (ou package) e você terá que evitar métodos estáticos / finais.
Mockito, na minha opinião, intencionalmente não fornece suporte para esses tipos de simulações, já que usar esses tipos de construções de código são odores de código e código mal projetado.
Porém, existem estruturas que suportam simulação para métodos privados e estáticos.
Powermock estende recursos de outras estruturas como EasyMock e Mockito e fornece a capacidade de simular métodos estáticos e privados.
# 1) Como: Powermock faz isso com a ajuda da manipulação de bytecode customizado para suportar métodos privados e estáticos de simulação, classes finais, construtores e assim por diante.
# 2) Pacotes com suporte: Powermock fornece 2 APIs de extensão - uma para Mockito e outra para easyMock. Por causa deste artigo, vamos escrever exemplos com a extensão Mockito para power mock.
# 3) Sintaxe :Powermockito tem uma sintaxe quase semelhante ao Mockito, exceto alguns métodos adicionais para simular métodos estáticos e privados.
# 4) Configuração do Powermockito
Para incluir a biblioteca Mockito em projetos baseados no Gradle, abaixo estão as bibliotecas a serem incluídas:
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '1.7.4' testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.7.4'Dependências semelhantes também estão disponíveis para o maven.
Powermock-api-mockito2 - A biblioteca é necessária para incluir extensões Mockito para Powermockito.
Powermock-module-junit4 - O módulo é necessário para incluir PowerMockRunner (que é um runner personalizado a ser usado para executar testes com PowerMockito).
Um ponto importante a ser observado aqui é que o PowerMock não oferece suporte ao executor de teste Junit5. Portanto, os testes precisam ser escritos no Junit4 e os testes precisam ser executados com o PowerMockRunner.
Para usar PowerMockRunner - a classe de teste precisa ser anotada com @RunWith (PowerMockRunner.class)
Agora vamos discutir, zombando dos métodos privados, estáticos e vazios em detalhes!
Zombar de métodos privados
Zombar de métodos privados, que são chamados internamente de um método em teste, pode ser inevitável em determinados momentos. Usando o powermockito, isso é possível e a verificação é feita usando um novo método chamado ‘verifyPrivate’
Vamos levar aExemplo onde o método em teste chama um método privado (que retorna um booleano). Para fazer o stub desse método para retornar verdadeiro / falso dependendo do teste, um stub precisa ser configurado nesta classe.
Para este exemplo, a classe em teste é criada como uma instância espiã com simulação em algumas invocações de interface e invocação de método privado.
Pontos importantes para o Método Privado Simulado:
# 1) O método de teste ou classe de teste precisa ser anotado com @ PrepareForTest (ClassUnderTest). Esta anotação informa ao powerMockito para preparar certas classes para teste.
Estas serão principalmente as classes que precisam ser Bytecode manipulado . Normalmente, para classes finais, classes que contêm métodos privados e / ou estáticos que precisam ser simulados durante o teste.
Exemplo:
@PrepareForTest(PriceCalculator.class)#dois) Para configurar o stub em um método privado.
Sintaxe - quando (instância simulada ou espiã, “privateMethodName”). thenReturn (// valor de retorno)
Exemplo:
when (priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false);# 3) Para verificar o método privado em stub.
Sintaxe - verifyPrivate (mockedInstance) .invoke (“privateMethodName”)
Exemplo:
verifyPrivate (priceCalculator).invoke('isCustomerAnonymous');Amostra de teste completa: Continuando o mesmo exemplo dos artigos anteriores, em que priceCalculator tem algumas dependências simuladas como itemService, userService etc.
Criamos um novo método chamado - calculPriceWithPrivateMethod, que chama um método privado dentro da mesma classe e retorna se o cliente é anônimo ou não.
@Test @PrepareForTest(PriceCalculator.class) public void calculatePriceForAnonymous_witStubbedPrivateMethod_returnsCorrectPrice() throws Exception { // Arrange ItemSku item1 = new ItemSku(); item1.setApplicableDiscount(5.00); item1.setPrice(100.00); double expectedPrice = 90.00; // Setting up stubbed responses using mocks when(priceCalculatorSpy, 'isCustomerAnonymous').thenReturn(false); when(mockedItemService.getItemDetails(123)).thenReturn(item1); // Act double actualDiscountedPrice = priceCalculatorSpy.calculatePriceWithPrivateMethod(123); // Assert verifyPrivate(priceCalculator).invoke('isCustomerAnonymous'); assertEquals(expectedPrice, actualDiscountedPrice); } Zombar de métodos estáticos
Os métodos estáticos podem ser simulados de maneira semelhante à que vimos para os métodos privados.
Quando um método em teste envolve o uso de um método estático da mesma classe (ou de uma classe diferente), precisaremos incluir essa classe na anotação prepareForTest antes do Teste (ou na classe de teste).
Pontos importantes para métodos de simulação estática:
# 1) O método de teste ou classe de teste precisa ser anotado com @ PrepareForTest (ClassUnderTest). Semelhante à simulação de métodos / classes privados, isso também é necessário para classes estáticas.
#dois) Uma etapa extra necessária para métodos estáticos é - mockStatic (// nome da classe estática)
Exemplo:
mockStatic(DiscountCategoryFinder.class) # 3) Configurar o stub em um método estático é tão bom quanto fazer o stub de qualquer método em qualquer outra interface / instância simulada de classe.
Por exemplo: Para criar um stub getDiscountCategory () (que retorna um enum DiscountCategory com os valores PREMIUM & GENERAL) do método estático da classe DiscountCategoryFinder, basta fazer o stub da seguinte maneira:
when (DiscountCategoryFinder. getDiscountCategory ()).thenReturn(DiscountCategory. PREMIUM );# 4) Para verificar a configuração simulada no método final / estático, o método verifyStatic () pode ser usado.
Exemplo:
verifyStatic (DiscountCategoryFinder.class, times (1));Zombando de métodos de vazio
Vamos primeiro tentar entender que tipo de casos de uso podem envolver métodos vazios de stub:
# 1) Chamadas de método, por exemplo - que envia uma notificação por email durante o processo.
Por exemplo :Suponha que você altere a senha de sua conta de internet banking, assim que a alteração for bem-sucedida, você receberá uma notificação por e-mail.
Isso pode ser considerado como / changePassword como uma chamada POST para a API do banco que inclui uma chamada de método void para enviar uma notificação por email ao cliente.
#dois) Outro exemplo comum da chamada do método void são as solicitações atualizadas para um banco de dados que recebem alguma entrada e não retornam nada.
Métodos vazios de stub (ou seja, os métodos que não retornam nada, ou então lançam uma exceção), podem ser tratados usando funções doNothing (), doThrow () e doAnswer (), doCallRealMethod () . Requer que o stub seja configurado usando os métodos acima de acordo com as expectativas do teste.
Além disso, observe que todas as chamadas de método void são simuladas por padrão para doNothing (). Portanto, mesmo se uma configuração simulada explícita não for feita em VAZIO chamadas de método, o comportamento padrão ainda é doNothing ().
Vejamos exemplos para todas essas funções:
Para todos os exemplos, vamos supor que haja uma classe StudentScoreUpdates que tem um método calculeSumAndStore (). Este método calcula a soma das pontuações (como entrada) e chama um vazio método updateScores () na instância de databaseImplementation.
public class StudentScoreUpdates { public IDatabase databaseImpl; public StudentScoreUpdates(IDatabase databaseImpl) { this.databaseImpl = databaseImpl; } public void calculateSumAndStore(String studentId, int() scores) { int total = 0; for(int score : scores) { total = total + score; } // write total to DB databaseImpl.updateScores(studentId, total); } }Estaremos escrevendo testes de unidade para a chamada do método simulado com os exemplos abaixo:
# 1) doNothing () - doNothing () é o comportamento padrão para chamadas de método void no Mockito, ou seja, mesmo se você verificar uma chamada no método void (sem configurar explicitamente um void para doNothing (), a verificação ainda será bem-sucedida)
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int() scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore('student1', scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(anyString(), anyInt()); } Outros usos junto com doNothing ()
para) Quando o método void é chamado várias vezes e você deseja configurar diferentes respostas para diferentes chamadas, como - doNothing () para a primeira chamada e lançar uma exceção na próxima chamada.
Por exemplo :Configure a simulação como esta:
Mockito. doNothing ().doThrow(new RuntimeException()).when(mockDatabase).updateScores( anyString (), anyInt ());b) Quando você quiser capturar os argumentos com os quais o método void foi chamado, a funcionalidade ArgumentCaptor no Mockito deve ser usada. Isso fornece uma verificação adicional dos argumentos com os quais o método foi chamado.
Exemplo com ArgumentCaptor:
public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabase); int() scores = {60,70,90}; Mockito.doNothing().when(mockDatabase).updateScores(anyString(), anyInt()); ArgumentCaptor studentIdArgument = ArgumentCaptor.forClass(String.class); // Act studentScores.calculateSumAndStore('Student1', scores); // Assert Mockito.verify(mockDatabase, Mockito.times(1)).updateScores(studentIdArgument.capture(), anyInt()); assertEquals('Student1', studentIdArgument.getValue()); } # 2) doThrow ()- Isso é útil quando você simplesmente deseja lançar uma exceção quando o método void é chamado a partir do método em teste.
Por exemplo:
Mockito.doThrow(newRuntimeException()).when(mockDatabase).updateScores ( anyString (), anyInt ());# 3) doAnswer ()- doAnswer () simplesmente fornece uma interface para fazer alguma lógica personalizada.
Por exemplo. Modificar algum valor por meio dos argumentos passados, retornando valores / dados personalizados que um stub normal não poderia ter retornado, especialmente para métodos void.
Para fins de demonstração - eu criei o método void updateScores () para retornar um “ responda() ”E imprime o valor de um dos argumentos que deveriam ter sido passados quando o método deveria ter sido chamado.
como selecionar o botão de rádio no selênio webdriver
Exemplo de código:
@Test public void calculateSumAndStore_withValidInput_shouldCalculateAndUpdateResultInDb() { // Arrange studentScores = new StudentScoreUpdates(mockDatabaseImpl); int() scores = {60,70,90}; Mockito.doCallRealMethod().when(mockDatabaseImpl).updateScores(anyString(), anyInt()); doAnswer(invocation -> { Object() args = invocation.getArguments(); Object mock = invocation.getMock(); System.out.println(args(0)); return mock; }).when(mockDatabaseImpl).updateScores(anyString(), anyInt()); // Act studentScores.calculateSumAndStore('Student1', scores); // Assert Mockito.verify(mockDatabaseImpl, Mockito.times(1)).updateScores(anyString(), anyInt()); } # 4) doCallRealMethod ()- Simulações parciais são semelhantes a stubs (onde você pode chamar métodos reais para alguns dos métodos e remover o resto).
Para métodos void, mockito fornece uma função especial chamada doCallRealMethod () que pode ser usada quando você está tentando configurar o mock. O que isso fará é chamar o método real void com os argumentos reais.
Por exemplo:
Mockito. doCallRealMethod ().when(mockDatabaseImpl).updateScores( anyString (), anyInt ());dicas e truques
# 1) Incluindo várias classes estáticas no mesmo método / classe de teste- Usando PowerMockito se houver necessidade de simular várias classes estáticas ou finais, os nomes das classes em @ PrepareForTest a anotação pode ser mencionada como um valor separado por vírgula como uma matriz (ela essencialmente aceita uma matriz dos nomes das classes).
Exemplo:
@PrepareForTest({PriceCalculator.class, DiscountCategoryFinder.class})Conforme mostrado no exemplo acima, suponha que PriceCalculator e DiscountCategoryFinder sejam classes finais que precisam ser simuladas. Ambos podem ser mencionados como uma matriz de classes na anotação PrepareForTest e podem ser fragmentados no método de teste.
# 2) Posicionamento do atributo PrepareForTest - O posicionamento desse atributo é importante com relação ao tipo de testes incluídos na classe Teste.
Se todos os testes precisam usar a mesma classe final, então faz sentido mencionar este atributo no nível da classe de teste, o que significa simplesmente que a classe preparada estará disponível para todos os Métodos de Teste. Ao contrário disso, se a anotação for mencionada no método de teste, ela estará disponível apenas para aqueles testes específicos
Conclusão
Neste tutorial, discutimos várias abordagens para simulação de métodos estáticos, finais e vazios.
Embora o uso de muitos métodos estáticos ou finais atrapalhe a testabilidade e, ainda assim, há suporte disponível para teste / simulação para ajudar na criação de testes de unidade a fim de obter maior confiança no código / aplicativo, mesmo para código legado que geralmente não é usado para ser projetado para testabilidade.
Para métodos estáticos e finais, o Mockito não tem um suporte pronto para uso, mas bibliotecas como o PowerMockito (que herdam muitas coisas do Mockito) fornecem esse suporte e precisam executar a manipulação de bytecode para oferecer suporte a esses recursos.
O Mockito pronto para usar oferece suporte a métodos vazios de stub e fornece vários métodos, como doNothing, doAnswer, doThrow, doCallRealMethod etc. e pode ser usado de acordo com os requisitos do teste.
As perguntas mais frequentes da entrevista Mockito são resumidas em nosso próximo tutorial.
PREV Tutorial | PRÓXIMO Tutorial
Leitura recomendada
- Tutorial Mockito: Framework Mockito para simulação em testes de unidade
- As 12 principais perguntas da entrevista Mockito (Entrevista Mocking Framework)
- Estático em C ++
- Threads Java com métodos e ciclo de vida
- Criando Mocks e Spies no Mockito com exemplos de código
- Diferentes tipos de matchers fornecidos por Mockito
- Métodos e técnicas de prevenção de defeitos
- Como usar métodos no SoapUI para execução de testes em massa - Tutorial # 10 do SoapUI