![](/img/trans.png)
[英]InvalidUseOfMatchersException when using Matchers.eq() with other mocked values
[英]Invalid use of argument matcher when calling spy method inside Matchers.eq
在單元測試期間,我們遇到了來自Mockito
的奇怪錯誤,乍一看可能看起來微不足道,但是經過更深入的研究,我們找不到它為什么如此工作。 請查看以下代碼和引發的錯誤。
碼
import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
//...
@InjectMocks
@Spy
private MyWebSocket webSocket;
@Mock
private WebSocketUtils webSocketUtils;
@Test
public void myTest() throws IOException {
WebSocketSession session1 = Mockito.mock(WebSocketSession.class);
WebSocketSession session2 = Mockito.mock(WebSocketSession.class);
WebSocketSession session3 = Mockito.mock(WebSocketSession.class);
webSocket.getUserNameWebSocketSessions().put("user1", session1);
webSocket.getUserNameWebSocketSessions().put("user1", session2);
webSocket.getUserNameWebSocketSessions().put("user2", session3);
Mockito.doReturn(new CustomWebSocketMessage<UserSessionInfo>().config(Command.USER_SESSION_INFO).data(new UserSessionInfo()))
.when(webSocket)
.buildUserSessionInfoWebSocketMessage(Mockito.any());
webSocket.onUserPermissionsChange(new UserPermissionsChangedEvent(Collections.singletonList("user1"), this));
ArgumentCaptor<CustomWebSocketMessage> messageCaptor = ArgumentCaptor.forClass(CustomWebSocketMessage.class);
Mockito.verify(webSocketUtils).sendMessageToMultipleUsers(messageCaptor.capture(), Matchers.eq(webSocket.getUserNameWebSocketSessions().get("user1")));
CustomWebSocketMessage message = messageCaptor.getValue();
Assertions.assertThat(message.getMessagePayload().getConfig().getCommand()).isEqualTo(Command.USER_SESSION_INFO.name());
Assertions.assertThat(message.getMessagePayload().getData()).isInstanceOf(UserSessionInfo.class);
}
錯誤
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at ... (Name of the bussines package)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
如您所見,第一個參數是捕獲器,第二個參數是Mockito
包中的Matcher
。 我不知道為什么它不起作用,但是解決它的原因是將獲取會話從Matchers.eq()
方法轉移到變量聲明。
固定
Collection<WebSocketSession> sessions = webSocket.getUserNameWebSocketSessions().get("user1");
Mockito.verify(webSocketUtils).sendMessageToMultipleUsers(messageCaptor.capture(), Matchers.eq(sessions));
誰能解釋我為什么將其移至變量?
這是因為Mockito匹配器通過副作用起作用 。 這意味着Matcher調用不應包含復雜的表達式,並且絕對不應包含調用Mockito模擬或間諜的表達式。
對於Java之類的強類型語言,Mockito無法以看起來像int
的易於區分的返回值來表示或編碼eq(0)
或gt(5)
或anyInt()
類的概念 。 Mockito甚至沒有嘗試。 相反,Mockito將狀態保持在隱藏的堆棧上,並依靠對方法調用的巧妙而精致的排序來操縱和查詢它:
verify
,傳入一個對象 when
存根具有相似的規則(零個或多個匹配項,一個對模擬方法的調用,一個對when
調用,一個或多個thenVerb
調用)時,與doVerb
存根(一個對doVerb
調用,零個或多個thenVerb
調用,一次調用when
,零個或多個匹配器,一次調用模擬方法。 但是,Mockito在您的測試方法中看不到代碼,因此無法判斷下一步是什么。 它只能在您通過調用靜態方法或在模擬對象上調用方法與Mockito交互時看到。 這意味着有時它沒有給您足夠的異常(錯誤地通過了測試),有時它給了您太多(如此處所示),有時它給了您錯誤的異常消息或在錯誤的方法上標記了異常。
我將使用在Mockito匹配器如何工作中使用的注釋約定? 上面鏈接的答案,它顯示了Java在調用方法之前如何從左到右評估參數表達式。
在您的特定情況下,您的原始方法遵循以下模式:
Mockito.verify(webSocketUtils).sendMessageToMultipleUsers(
// [1] [6]
messageCaptor.capture(),
// [2]
Matchers.eq(webSocket.getUserNameWebSocketSessions().get("user1")));
// [5] [3] [4]
webSocketUtils
不需要評估,因此首先正確調用verify
capture
就像匹配器一樣,所以這仍然是正確的 webSocket
是間諜,因此getUserNameWebSocketSessions()
是對模擬的調用。 哎呀! 現在,Mockito認為這是您正在驗證的調用,並且您已經為無參數方法調用准備好了匹配器。 看起來像是無效的匹配器! 此時執行停止,因此您甚至不必調用第二個匹配器[5]或打算模擬的方法[6]。
修復后:
Collection<WebSocketSession> sessions =
webSocket.getUserNameWebSocketSessions().get("user1");
// [1]
Mockito.verify(webSocketUtils).sendMessageToMultipleUsers(
// [2] [5]
messageCaptor.capture(), Matchers.eq(sessions));
// [3] [4]
verify
在正確的時間發生。 capture
將一個匹配器放入堆棧。 eq
將另一個匹配器放到堆棧中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.