PowerMockito: NotamockException на макет
Бит сложной настройки. Robolectric, конфигурация на основе правил PowerMockito.
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
// Using "PrepareOnlyThis" prevents powermock from trying to instrument the whole hierarchy,
// part of which we've ignored (android.os.* in this case)
@PrepareOnlyThisForTest({ServiceCallbackBase.class}) // this class extends Handler,
// so we need PrepareOnlyThis. It also has some final methods we need to verify()
public class ServiceBaseTests {
private class Foo {
// nothing
}
@Rule
public PowerMockRule rule = new PowerMockRule();
private ServiceCallbackBase<Object, Foo> setupCallback( boolean hasValidContext, boolean allContextsCanceled ) {
ServiceCallbackBase<Object, Foo> callback = PowerMockito.mock( ServiceCallbackBase.class );
// EDIT: I have converted these to PowerMockito.doReturn()s to no avail.
PowerMockito.when( callback.hasValidContext() ).thenReturn( hasValidContext );
PowerMockito.when( callback.allContextsAreCanceled( any( Message.class ) ) ).thenReturn( allContextsCanceled );
PowerMockito.doNothing().when( callback ).preSendMessage( any( Message.class ) );
return callback;
}
Должно быть довольно рутиной. Но всякий раз, когда я пытаюсь вызвать verify
в одном из этих экземпляров "обратного вызова", например:
private void test_notifyCallback( boolean isFromCache ) {
ServiceCallbackBase<Object, Foo> callback = setupCallback( true, false );
uut.addHandler( TestEnum.FOO, callback );
uut.addHandler( TestEnum.BAR, PowerMockito.mock( ServiceCallbackBase.class ) );
uut.addHandler( TestEnum.BAZ, PowerMockito.mock( ServiceCallbackBase.class ) );
Response<Foo> foo = new Response<>( new Foo(), new ResponseStatus( 0, "Error" ) );
uut.handleCallBack( TestEnum.FOO, foo, isFromCache );
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass( Message.class );
// this line throws the error.
verify( callback ).preSendMessage( captor.capture() );
assertThat( captor.getValue().what ).isEqualTo( TestEnum.FOO.ordinal() );
assertThat( captor.getValue().obj ).isEqualTo( foo );
assertThat( captor.getValue().arg1 ).isEqualTo( isFromCache ? 1 : 0 );
}
Я получаю такую ошибку:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type ServiceCallbackBase$$EnhancerByMockitoWithCGLIB$$9acf906b and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMethod();
Он четко и явно "улучшен" mockito, а PowerMock не использует метод verify() вместо Mockito.verify()
... что дает?
EDIT: это в некотором роде больше и в некотором смысле более запутанном.
Я собираюсь создать еще один тестовый класс для тестирования самой ServiceCallbackBase. Если я удалю тесты из этого класса, эти тесты пройдут. Следующий фрагмент в другом классе приводит к ошибкам вышеприведенных тестов.
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class ServiceCallbackBaseTests {
@Test
public void test_nothing(){
}
private ServiceCallbackBase<Object, String> uutSpy;
@Before
public void setup(){
uutSpy = mock( ServiceCallbackBase.class );
}
}
Ответы
Ответ 1
Я не могу создать ваш пример, но мне удалось написать этот мини-проект, который создает очень похожую проблему:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareOnlyThisForTest({ServiceCallbackBase.class, Dummy.class})
public class MainActivityTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Test
public void test1() throws Exception {
try {
//This Mockito.withSettings() thing is important to make the test fail!
ServiceCallbackBase callback = PowerMockito.mock( ServiceCallbackBase.class, Mockito.withSettings());
callback.dispatchMessage(null);
Mockito.verify(callback).dispatchMessage(null);
} catch (Exception e){
e.printStackTrace();
Assert.fail();
}
}
}
(Обратите внимание на Mockito.withSettings(), я не знаю, почему, но это заставляет тест сбой)
Печать
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type ServiceCallbackBase$$EnhancerByMockitoWithCGLIB$$62776c54 and is not a mock!
Make sure you place the parenthesis correctly!
......
Ну, это абсолютно выглядит как проблема с загрузкой, mockito сравнивает ServiceCallbackBase $$ EnhancerByMockitoWithCGLIB $$ и т.д., загруженные Powermock с тем же загруженным Robolectric (очевидно, возвращающим false в этом сравнении)
Затем мне удалось сделать тестовую работу простым добавлением "org.powermock.*"
в строку @PowerMockIgnore...
, это:
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*", "org.powermock.*"})
Это простое изменение заставило мой тест работать, и я действительно надеюсь, что вы тоже заработаете.
Ответ 2
Я столкнулся с этой проблемой. В проекте PowerMock есть проблема: https://github.com/jayway/powermock/issues/593
Но никаких комментариев ни от одного из разработчиков powermock.