2016-09-13 3 views
0

Я пытаюсь познакомиться с Mockito Captor, но получаю как исключение NullPointerException, так и InvalidUseOfMatchersException. У меня такое чувство, что я делаю что-то неправильно и/или неправильно понимаю метод захвата.Spring-Boot: Mockito Captor: NullPointerException и InvalidUseOfMatchersException

Вот мой тестирование класс:

@Test 
public void testFindByClientIdAndBatchDateBetween() { 

    DateTime todayDateTime = new DateTime().withTimeAtStartOfDay(); 

    mockedTransactRepViewModel.capture().setClientId("123456"); 
    mockedTransactRepViewModel.capture().setBatchDate(todayDateTime.toDate()); 
    mockTransactRepViewRepository.save(mockedTransactRepViewModel.capture()); 

    verify(mockTransactRepViewRepository).findByClientIdAndClDateBetween("123456", todayDateTime.toDate(), 
                   todayDateTime.plusDays(1).toDate()).get(0); 

    String mockClientId = mockedTransactRepViewModel.getValue().getClientId(); 
    assertThat(mockClientId.equals("123456")); 

    verify(mockTransactRepViewRepository, times(1)).save(mockedTransactRepViewModel.capture()); 
} 

Edit: Полный трассировки стека:

java.lang.NullPointerException 
    at domain.TransactRepViewRepositoryTest.testFindByClientIdAndBatchDateBetween(TransactRepViewRepositoryTest.java:84) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.mockito.internal.junit.JUnitRule$1.evaluate(JUnitRule.java:16) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) 
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) 


org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced argument matcher detected here: 

-> at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 

You cannot use argument matchers outside of verification or stubbing. 
Examples of correct usage of argument matchers: 
    when(mock.get(anyInt())).thenReturn(null); 
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); 
    verify(mock).someMethod(contains("foo")) 

Also, this error might show up because you use argument matchers with methods that cannot be mocked. 
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode(). 
Mocking methods declared on non-public parent classes is not supported. 
+0

Добавить полный стек или сообщения – Jens

+0

Отредактировано мое сообщение выше. –

ответ

2

похитители не совсем так, как Вы имеете их. Вы должны только позвонить capture, чтобы встать для аргумента во время вызова verify, а затем получить захваченное значение или значения с помощью getValue или getValues.

/* BAD */ mockedTransactRepViewModel.capture().setClientId("123456"); 

В мире без похитителей, если вам нужно проверить значение параметра, которое было получено в рамках взаимодействия с макетом, вам нужно будет использовать Mockito matchers (eq или gt, например,), или вам нужно будет написать совпадение Hamcrest, чтобы проверить, какую сумму вы получите.

/* in your system under test */ 
someSystem.setPowerLevel(9001); 
someSystem.interact(new Widget(4)); 

/* in your test */ 
verify(mockSystem).setPowerLevel(gt(9000)); // greater than 9000 
verify(mockSystem).interact(argThat(isAWidgetWithParameter(4))); 

Естественно, это делает его трудно контролировать различные свойства объекта, или получить ссылку на экземпляр, который вы можете пройти в другом месте. Вот тут и появляются похитители, созданные либо через ArgumentCaptor.forClass, либо через аннотацию @Captor.

/* in your system under test */ 
someSystem.interact(new Widget(4)); 

/* in your test */ 
verify(mockSystem).interact(widgetCaptor.capture()); 
Widget widgetInteractedWith = widgetCaptor.getValue(); 
assertEquals(4, widgetInteractedWith.getParameter()); 
doOtherAssertionsOn(widgetInteractedWith); 

За кулисами, метод capture фактически возвращает null, потому что вы никогда не имел в виду, чтобы взаимодействовать с возвращаемым значением этого метода. Как и другие матчи Mockito, вызов возвращает фиктивное значение, а Mockito устанавливает некоторое внутреннее состояние, поэтому он знает, что он заполняет Captor, а не пытается сопоставить каждый аргумент равенства. Я написал более длинный ответ на how Mockito matchers work, в котором объясняется больше об этом скрытом стеке.

+0

Привет, спасибо за ваш ответ, но мне трудно понять это. Я решил свою проблему следующим образом: 'ArgumentCaptor transactRepViewModelArgumentCaptor = ArgumentCaptor.forClass (TransactRepViewModel.class); \t \t проверить (mockTransactRepViewRepository, times (1)). Save (transactRepViewModelArgumentCaptor.capture()); \t \t assertEquals ("123456", transactRepViewModelArgumentCaptor.getValue(). GetClientId()); ' –

+0

Но я не уверен, что я доволен этим тестом. Я думаю, что мне нужно перейти на тестирование интеграции, хотя мои администраторы db против этого. –

+1

@Deniss Ваш новый тест выглядит отлично. Важная часть состоит в том, что вы вызываете 'capture' только из вызова метода' verify', а затем взаимодействуете с захваченным значением, используя 'getValue' впоследствии. Что касается вашей тестовой области, вам решать, и ваша команда должна решить, основываясь на общем контракте вашей тестируемой системы. –

Смежные вопросы