在 Java 接口中模拟方法时 Mockito 出现问题
Issue with Mockito when mocking a method in Java Interface
我在使用 Junit5 和 Mockito 3.8 模拟 Java 接口中的方法时遇到问题。测试失败,原因:
Wanted but not invoked:
remoteCommands.getServiceStatus("ABC");
-> at com.acme.CommandHandlerTest.testServiceName(CommandHandlerTest.java:40)
Actually, there were zero interactions with this mock.
它在 CommandHandlerTest.java 的第 40 行失败,即
verify(remoteCommands).getServiceStatus(serviceName);
但是,当我调试代码时,我可以看到正在执行的方法,所以我知道与此方法有 1 次交互,但 Mockito 无法识别它。
如果我遗漏了什么,你能告诉我吗?我的代码文件如下,
CommandHandlerTest.java
package com.acme;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.rmi.RemoteException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class CommandHandlerTest {
private CommandHandler commandHandler;
@Mock
IRemoteCommandsImpl remoteCommands;
@BeforeEach
void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
void testDoCommand_serviceName() throws RemoteException {
commandHandler = new CommandHandler();
String serviceName = "ABC";
int mockValue = 4000;
when(remoteCommands.getServiceStatus(eq(serviceName))).thenReturn(mockValue);
commandHandler.printServiceStatus(serviceName);
verify(remoteCommands).getServiceStatus(serviceName);
}
}
CommandHandler.java
package com.acme;
public class CommandHandler {
private IRemoteCommands remoteCommands;
public CommandHandler(){
}
public void printServiceStatus(String service) {
remoteCommands = new IRemoteCommandsImpl();
int serviceStatus = 0;
try {
serviceStatus = remoteCommands.getServiceStatus(service);
System.out.println("CommandHandler->serviceStatus: "+serviceStatus);
} catch (Exception e) {
e.getMessage();
}
}
}
IRemoteCommands.java
package com.acme;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IRemoteCommands extends Remote
{
public int getServiceStatus(String serviceName) throws RemoteException;
}
IRemoteCommandsImpl.java
package com.acme;
import java.rmi.RemoteException;
public class IRemoteCommandsImpl implements IRemoteCommands{
@Override
public int getServiceStatus(String serviceName) throws RemoteException {
return 1000;
}
}
在您的 CommandHandler
中,您创建了 IRemoteCommandsImpl
的新实例并将其分配给私有 remoteCommands
字段。
这意味着您模拟的 remoteCommands
未被测试对象使用。
您需要重构您的代码并提供 remoteCommands
给 CommandHandler
,最好由构造函数提供:
public class CommandHandler {
private final IRemoteCommands remoteCommands;
public CommandHandler(IRemoteCommands remoteCommands) {
this.remoteCommands = remoteCommands;
}
// ...
}
最重要的是:
- 如果您使用
MockitoExtension
,则不需要 MockitoAnnotations.openMocks(this);
我在使用 Junit5 和 Mockito 3.8 模拟 Java 接口中的方法时遇到问题。测试失败,原因:
Wanted but not invoked:
remoteCommands.getServiceStatus("ABC");
-> at com.acme.CommandHandlerTest.testServiceName(CommandHandlerTest.java:40)
Actually, there were zero interactions with this mock.
它在 CommandHandlerTest.java 的第 40 行失败,即
verify(remoteCommands).getServiceStatus(serviceName);
但是,当我调试代码时,我可以看到正在执行的方法,所以我知道与此方法有 1 次交互,但 Mockito 无法识别它。
如果我遗漏了什么,你能告诉我吗?我的代码文件如下,
CommandHandlerTest.java
package com.acme;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.rmi.RemoteException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class CommandHandlerTest {
private CommandHandler commandHandler;
@Mock
IRemoteCommandsImpl remoteCommands;
@BeforeEach
void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
void testDoCommand_serviceName() throws RemoteException {
commandHandler = new CommandHandler();
String serviceName = "ABC";
int mockValue = 4000;
when(remoteCommands.getServiceStatus(eq(serviceName))).thenReturn(mockValue);
commandHandler.printServiceStatus(serviceName);
verify(remoteCommands).getServiceStatus(serviceName);
}
}
CommandHandler.java
package com.acme;
public class CommandHandler {
private IRemoteCommands remoteCommands;
public CommandHandler(){
}
public void printServiceStatus(String service) {
remoteCommands = new IRemoteCommandsImpl();
int serviceStatus = 0;
try {
serviceStatus = remoteCommands.getServiceStatus(service);
System.out.println("CommandHandler->serviceStatus: "+serviceStatus);
} catch (Exception e) {
e.getMessage();
}
}
}
IRemoteCommands.java
package com.acme;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IRemoteCommands extends Remote
{
public int getServiceStatus(String serviceName) throws RemoteException;
}
IRemoteCommandsImpl.java
package com.acme;
import java.rmi.RemoteException;
public class IRemoteCommandsImpl implements IRemoteCommands{
@Override
public int getServiceStatus(String serviceName) throws RemoteException {
return 1000;
}
}
在您的 CommandHandler
中,您创建了 IRemoteCommandsImpl
的新实例并将其分配给私有 remoteCommands
字段。
这意味着您模拟的 remoteCommands
未被测试对象使用。
您需要重构您的代码并提供 remoteCommands
给 CommandHandler
,最好由构造函数提供:
public class CommandHandler {
private final IRemoteCommands remoteCommands;
public CommandHandler(IRemoteCommands remoteCommands) {
this.remoteCommands = remoteCommands;
}
// ...
}
最重要的是:
- 如果您使用
MockitoExtension
,则不需要
MockitoAnnotations.openMocks(this);