"java.util.NoSuchElementException: No value present at java.util.Optional.get" 在使用模拟的 Spock 测试中

"java.util.NoSuchElementException: No value present at java.util.Optional.get" in a Spock test using mocks

我正在尝试为以下方法编写 groovy 单元测试:

public Set<ObjectName> getAll()
{

    return getMBeanServerConnection().map(mbsc ->
    {
        try
        {
            return mbsc.queryNames(null, null);
        }
        catch (IOException e)
        {
            logger.log(Level.SEVERE, "An exception was thrown: ", e);
            return Collections.<ObjectName>emptySet();
        }
    }).get();
}

该方法调用以下内容:

    private Optional<MBeanServerConnection> getMBeanServerConnection()
{
    return virtualMachineHelper.getMb();
}

然后:

public Optional<MBeanServerConnection> getMb()
{
    VirtualMachine virtualMachine = getOmsVirtualMachine();
    if (virtualMachine == null)
    {
        return Optional.empty();
    }
    try
    {
        Properties props = virtualMachine.getAgentProperties();
        String connectorAddress =
            props.getProperty(JMX_REMOTE_PROPERTY);

        JMXServiceURL url = new JMXServiceURL(connectorAddress);
        JMXConnector connector = JMXConnectorFactory.connect(url);
        MBeanServerConnection mbsc = connector.getMBeanServerConnection();
        return Optional.of(mbsc);
    }
    catch (IOException e)
    {
        logger.log(Level.SEVERE, "An exception was thrown: ", e);
        return Optional.empty();
    }
}

这只是一种将调用转发给 mbsc.queryNames(null, null)

的方法

我正在尝试测试调用 getAll() 时 mbsc.queryNames(null, null) 被调用一次。

我有以下代码:

def virtualMachineHelperMock = Mock(VirtualMachineHelper)
def mBeanServerConnection = Mock(MBeanServerConnection)

ObjectNamesRepository objectNamesRepository = new ObjectNamesRepository(virtualMachineHelperMock)

void setup() {
    virtualMachineHelperMock.getMb() >> Optional.of(mBeanServerConnection)
}

def "when calling getAll then queryNames is called from mBeanServerConnection"() {
    when:
    objectNamesRepository.getAll()

    then:
    1 * mBeanServerConnection.queryNames(null, null)
}

但这会产生以下错误:

java.util.NoSuchElementException: No value present

at java.util.Optional.get(Optional.java:135)
at com.ullink.ulconsole.repository.ObjectNamesRepository.getAll(ObjectNamesRepository.java:73)
at com.ullink.ulconsole.repository.ObjectNamesRepositorySpec.GetAll(ObjectNamesRepositorySpec.groovy:32)

这是因为没有记录 mbsc.queryNames(null, null) 调用的存根响应,所以 mock returns the default value: null. And the contract of Optional.map() 如下:

If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result. Otherwise return an empty Optional.

您从 map() 调用中得到一个空的 Optional,因此异常。

要解决此问题,您可以在同一交互中存根调用,如 Spock documentation:

中所述
1 * mBeanServerConnection.queryNames(null, null) >> Collections.emptySet()