本质上,我有一个 Java 类,它在套接字 channel 上执行选择,并且我想对 channel 进行 stub ,以便我可以测试选择是否按预期工作。
例如,被测试的类大致是这样做的:
class TestedClass {
TestedClass(SocketChannel socket) { this.socket = socket }
// ...
SocketChannel socket;
// ...
void foo() {
// Wait a while for far end to close as it will report an error
// if we do it. But don't wait forever!
// A -1 read means the socket was closed by the other end.
// If we select on a read, we can check that, or time out
// after a reasonable delay.
Selector selector = Selector.open();
socket.configureBlocking(false);
socket.register(selector, SelectionKey.OP_READ);
while(selector.select(1000) == 0) {
Log.debug("waiting for far end to close socket...")
}
ByteBuffer buffer = ByteBuffer.allocate(1);
if (socket.read(buffer) >= 0) {
Log.debug("far end didn't close");
// The far end didn't close the connection, as we hoped
abort(AbortCause.ServerClosed);
}
Log.debug("far end closed");
}
}
我希望能够测试这样的东西:
def "test we don't shut prematurely" () {
when:
boolean wasClosedPrematurely
SocketChannel socket = Stub(@SocketChannel) {
// insert stub methods here ....
}
TestedClass tc = new TestedClass(socket)
tc.foo();
then:
wasClosedPrematurely == false
}
这基于一个真实的例子,但细节并不重要。总体目标是如何对支持选择的 SocketChannels 进行 stub ,这样我就不必创建一个真实的客户端来进行测试。
我也知道它比仅仅 stub SocketChannel 更复杂:似乎我需要拦截 Selector.open()
或以某种方式提供自定义系统默认 SelectorProvider。如果我只是 stub SocketChannel,当我尝试使用我的 stub 注册通过 Selection.open()
获得的选择器时,我会得到一个 IllegalSelectorException,不幸的是,基本 AbstractSelectableChannel#register
方法是最终。
但是我找不到任何有用的指示来说明如何或是否可以使用 Spock Mocks 实现这一点,而且这似乎是一个很常见的事情,所以在这里问一个很好的问题。有人可以帮忙吗?
最佳答案
Spock 使用 CGLIB模拟/ stub / spy 类。 CGLIB 无法覆盖 final方法。 SocketChannel有很多final方法(例如configureBlocking),但是CGLIB不会失败而是使用原始方法。由于 configureBlocking 是最终的,因此它会在您的测试中使用。
公共(public)最终 SelectableChannel configureBlocking( boolean block )
抛出 IOException
{
同步(regLock){
if (!isOpen())
抛出新的 ClosedChannelException();
if(阻塞==阻塞)
返回这个;
if ( block && hasValidKeys())
抛出新的 IllegalBlockingModeException();
implConfigureBlocking( block );
阻塞=阻塞;
}
返回这个;
}
因此,configureBlocking 需要初始化 regLock 变量,但是当您为此类创建 stub 时,该变量未初始化,并且您会在此处得到 NPE。
问题是如何处理它? 好吧,我想说,首先,尝试使用接口(interface)而不是类。 如果不可能,请尝试不要调用 final方法。 如果仍然不可能,您必须查看类(class)内部并找出应该 mock 的内容。 我看到的最后一个选项是进行完整的集成测试:创建两个套接字并连接它们。
关于java - 是否可以使用 Spock stub 或模拟 SocketChannel?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41185351/