O uso de PowerMockito.whenNew () não está sendo simulado e o método original é chamado

99

Eu tenho um código parecido com este abaixo:

Class A {
  public boolean myMethod(someargs) {
    MyQueryClass query = new MyQueryClass();
    Long id = query.getNextId();
    // some more code
  }
}
Class MyQueryClass     {
  ....
  public Long getNextId() {
    //lot of DB code, execute some DB query
    return id;
  }
}

Agora estou escrevendo um teste para A.myMethod(someargs). Quero pular o método real query.getNextId()e, em vez disso, retornar um valor de stub. Basicamente, eu quero zombar MyQueryClass.

Então, em meu caso de teste, usei:

MyQueryClass query = PowerMockito.mock(MyQueryClass.class);
PowerMockito.whenNew(MyQueryClass.class).withNoArguments().thenReturn(query);
when(query.getNextId()).thenReturn(1000000L);

boolean b = A.getInstance().myMethod(args);

//asserts

Eu usei @RunWith(PowerMockRunner.class)e @PrepareForTest({MyQueryClass.class})no início da minha aula de teste.

Mas quando eu depuro o teste, ele ainda está chamando o método real getNextId()da MyQueryClassclasse.

O que estou perdendo aqui? Alguém pode ajudar porque sou novo no Mockito e no PowerMockito.

user3942446
fonte

Respostas:

219

Você precisa colocar a classe onde o construtor é chamado na @PrepareForTestanotação ao invés da classe que está sendo construída - veja a construção simulada de novos objetos .

No seu caso:

@PrepareForTest(MyQueryClass.class)

@PrepareForTest(A.class)

Mais general:

@PrepareForTest(NewInstanceClass.class)

@PrepareForTest(ClassThatCreatesTheNewInstance.class)

TrueDub
fonte
1
Muito obrigado. Funcionou agora depois de incluir a classe atual Eg A no @PrepareForTest.
user3942446 de
2
Também passo um tempo nisso. Obrigado @TrueDub. Porque a referência está desatualizada. Acabei de atualizá-lo. github.com/jayway/powermock/wiki/MockConstructor Diz: Use a anotação @PrepareForTest (ClassThatCreatesTheNewInstance.class) no nível de classe do caso de teste.
Victor Choy
4
Eu tenho o mesmo problema, mas esta solução não está funcionando para mim
dexter
3
Esta solução simplesmente não funcionará se você estiver usando eclemma para cobertura de código. Adicionar a classe em teste a @PrepareForTest resultará em 0% de cobertura para essa classe
ACV
2
A solução funcionará - o teste é executado corretamente. Obviamente, o eclemma não está equipado para lidar com o PowerMockito. A cobertura do código não faz parte desta questão.
TrueDub
3

Como @TrueDub mencionou em sua resposta aceita, você precisa adicionar a classe onde o construtor é chamado ao @PrepareForTest.

No entanto, se você fizer isso, a cobertura para essa classe, conforme relatado por eclemma e Sonar, será zero para essa classe

Wiki Powermockito

Vamos substituir Javassist por ByteBuddy (# 727) e deve ajudar a resolver esse problema antigo. Mas agora não há nenhuma maneira de usar o PowerMock com a instrumentação JaCoCo On-the-fly. E nenhuma solução alternativa para obter cobertura de código no IDE.

Portanto, a solução aqui seria refatorar o código real para usar uma fábrica estática que retornaria uma instância dessa classe e então simularia estaticamente.

ACV
fonte
Concordo com seu comentário.
Lathy
No entanto, isso não é um problema no Intellij.
ACV
0

Talvez você possa simplesmente usar

Mockito.doReturn(value).when(xxx)
Jiajianchen
fonte