본질적으로 소켓 채널에서 select를 수행하는 Java 클래스가 있으며 예상대로 select 작업을 테스트 할 수 있도록 채널을 스텁하고자합니다.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를 스텁 (stub)하는 방법입니다. 따라서 테스트 할 실제 클라이언트를 만들 필요가 없습니다.
또한 SocketChannel을 스터 빙하는 것보다 더 복잡하다는 것을 알고 있습니다. Selector.open()
을 가로 채거나 사용자 정의 시스템 기본 SelectorProvider를 제공해야하는 것처럼 보입니다. 간단히 SocketChannel을 스텁하면 Selection.open()
을 통해 얻은 셀렉터를 내 스텁에 등록하려고하면 IllegalSelectorException이 발생하고 AbstractSelectableChannel#register
메서드는 최종적으로 최종 메서드입니다.
하지만 Spock Mocks가 어떻게 가능한지 또는 유용한 지에 대한 유용한 정보를 찾을 수 없으므로 여기에 묻기 좋은 질문이 될 것 같습니다. 누구든지 도와 줄 수 있습니까?
스텁에 SocketChannel {새로운 예외()의 printStackTrace().}'configureBlocking 및 implConfigureBlocking 모두 호출되는 프로그램; 어떤 이유 때문에 후자의 스텁 메서드를 추가하는 것이 저에게 효과적이지 않습니다. 하지만 이것은 쇼 스토퍼가 아닙니다. #register 메소드가 호출 될 때입니다. 그것도 최종적이며 내부 (Java 7)는 소켓 공급자가 내부 개인 인터페이스를 구현하는지 확인하고, 그렇지 않은 경우 IllegalSelectorException을 던집니다. –
문제는 SelectorImpl :: register, # 117 번 줄에 있다고 생각합니다. if (! (var1 instanceof SelChImpl)) { 새로운 IllegalSelectorException()을 throw합니다. } else {... 솔직히 말해, 추상 클래스 (SocketChannel)의 인스턴스를 가질 수는 없지만 CGLIB에서는이를 가질 수 있습니다. 더러운 해킹으로 SocketChannel 대신 SocketChannelImpl을 사용하려고 시도하지만 전체 테스트를 검토하고 유형 (유닛, 수락, 통합)을 생각하고 추상 클래스를 스텁하는 등의 해킹 및 트릭을 사용하지 않고 다시 작성합니다. –
정확하게 : SelChImpl 인스턴스를 얻으려면 내부 구현을 모두 사용해야합니다. 그렇지 않으면이 검사를 부과하지 않는 자체 결과 중 하나를 반환하도록 'Selection.open()'을 유도해야합니다. 후자의 솔루션에 대한 선행 기술이 있기를 바랬습니다. 상호 연결된 유형을 다시 구현해야하는 것 같습니다. 어느 쪽이든, NIO의 디자인은 쉬운 단위 테스트를 방해하는 것 같습니다! 웹에 대한 언급은 거의 없습니다. –