私は、ソケットチャネルでselectを実行するJavaクラスを持っています。私は、選択したワークを期待通りにテストできるように、チャネルをスタブしたいと思います。SpockでSocketChannelをスタブまたはモックすることは可能ですか?
例えば、これはテストされているクラスが何をするかおおよそ次のとおりです。
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
}
この詳細は重要ではありません。一般的な目的は、selectをサポートするSocketChannelsをスタブする方法です。テストするために実際のクライアントを作成する必要はありません。
私はまた、SocketChannelをスタブするより複雑です:私はSelector.open()
を傍受するか、何らかの形でカスタムシステムのデフォルトSelectorProviderを提供する必要があるようです。私が単純にSocketChannelをスタブした場合、Selection.open()
で取得したセレクタをスタブに登録しようとするとIllegalSelectorExceptionが発生し、ベースのAbstractSelectableChannel#register
メソッドは残念ながら最後です。
しかし、これがSpock Mockでどのように可能かどうか、またSpock Mockで可能かどうかは分かりません。よく尋ねるとよい質問です。誰も助けることができますか?
スタブのSocketChannel {新しい例外()のprintStackTrace()}' configureBlockingとimplConfigureBlocking両方が呼び出される示します。なんらかの理由で、後者のスタブメソッドを追加することができません。しかし、これはショーストッパーではなく、#registerメソッドが呼び出されたときです。それは最終的なものであり、ソケットプロバイダが内部プライベートインターフェイスを実装していることを内部(Java 7)がチェックし、IllegalSelectorExceptionをスローします。 –
問題はSelectorImpl :: register、#117行にあると思います。 if(!(varI instanceof SelChImpl)){ 新しいIllegalSelectorException()をスローします。 } else {... 正に、抽象クラス(SocketChannel)のインスタンスを持つことはできませんが、CGLIBには抽象クラスのインスタンスがあります。 SocketChannelの代わりにSocketChannelを汚れたハックとして使用しようとしますが、テスト全体を見直し、タイプ(ユニット、受け入れ、統合)を考え、抽象クラスをスタブするようなハックやトリックを使わずに書き直します。 –
正確には、SelChImplインスタンスを取得するために内部実装全体を使用するか、何らかの形でこのチェックを行わない自分自身のものを返すために 'Selection.open()'を誘導する必要があります。私は、後者の解決策のためにいくつかの先行技術があるかもしれないことを望んでいました。これは、相互接続された種類の束を再実装する必要があるように思われるからです。いずれにせよ、NIOの設計は簡単な単体テストを妨げるようです!そして、ウェブ上のコメントはほとんどありません。 –