PowerMockito simula método estático único e objeto de retorno

98

Eu quero simular um método estático m1 de uma classe que contém 2 métodos estáticos, m1 e m2. E eu quero que o método m1 retorne um objeto.

Eu tentei o seguinte

1)

PowerMockito.mockStatic(Static.class, new Answer<Long>() {
         @Override
         public Long answer(InvocationOnMock invocation) throws Throwable {
            return 1000l;
         }
      });

Isso está chamando m1 e m2, que tem um tipo de retorno diferente, portanto, dá um erro de incompatibilidade de tipo de retorno.

2) PowerMockito.when(Static.m1(param1, param2)).thenReturn(1000l); Mas isso não é chamado quando m1 é executado.

3) PowerMockito.mockPartial(Static.class, "m1"); Apresenta um erro de compilador de que o mockPartial não está disponível, que obtive em http://code.google.com/p/powermock/wiki/MockitoUsage .

user1393653
fonte

Respostas:

135

O que você deseja fazer é uma combinação da parte 1 e toda a 2.

Você precisa usar o PowerMockito.mockStatic para habilitar a simulação estática para todos os métodos estáticos de uma classe. Isso significa que é possível fazer o stub usando a sintaxe when-thenReturn.

Mas a sobrecarga de 2 argumentos do mockStatic que você está usando fornece uma estratégia padrão para o que o Mockito / PowerMock deve fazer quando você chama um método que não foi explicitamente criado na instância do mock.

Do javadoc :

Cria simulação de classe com uma estratégia especificada para suas respostas às interações. É um recurso bastante avançado e normalmente você não precisa dele para escrever testes decentes. No entanto, pode ser útil ao trabalhar com sistemas legados. É a resposta padrão, portanto, será usada apenas quando você não fizer o stub da chamada do método.

A estratégia de stub padrão padrão é retornar apenas nulo, 0 ou falso para métodos de objeto, número e valor booleano. Ao usar a sobrecarga de 2 argumentos, você está dizendo "Não, não, não, por padrão, use o método de resposta desta subclasse de Resposta para obter um valor padrão. Ele retorna um Longo, portanto, se você tiver métodos estáticos que retornam algo incompatível com Longo, há um problema.

Em vez disso, use a versão 1-arg de mockStatic para habilitar o stub de métodos estáticos e, em seguida, use when-thenReturn para especificar o que fazer para um método específico. Por exemplo:

import static org.mockito.Mockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

class ClassWithStatics {
  public static String getString() {
    return "String";
  }

  public static int getInt() {
    return 1;
  }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStatics.class)
public class StubJustOneStatic {
  @Test
  public void test() {
    PowerMockito.mockStatic(ClassWithStatics.class);

    when(ClassWithStatics.getString()).thenReturn("Hello!");

    System.out.println("String: " + ClassWithStatics.getString());
    System.out.println("Int: " + ClassWithStatics.getInt());
  }
}

O método estático com valor de String é esboçado para retornar "Hello!", Enquanto o método estático com valor int usa o esboço padrão, retornando 0.

Tom Tresansky
fonte
1
Não há necessidade de repetir?
Balaji Boggaram Ramanarayan
Hmm ... meio que parece. Talvez o PowerMockito faça o replay do PowerMock para você? Eu também me pergunto sobre isso.
djangofan
3
Mas e se eu precisar ter certeza de que algum método estático é chamado com argumentos precisos?
elTomato
6
A @PrepareForTestanotação deve ser a classe que chama o método estático, não a classe onde o método estático está.
Hazel Troost
5
@HazelTroost - Não, o OP está certo. É a classe que contém o método estático que deve ser preparada para teste. Então, @PrepareForTest(ClassWithStatics.class)está certo.
arry36