kunerd
kunerd

Reputation: 1076

Netty, how to mock ChannelFuture/ChannelPromise?

I am using Netty 4.0 to create a distributed privacy preserving algorithm for my masters thesis. I do TDD and most of the time this works very well because of Netty's modular API. One problem I get stuck on last week is I do not know how to test code that depends on ChannelFutureListener. So lets say I have following code in my application:

public ChannelFuture close() {
    if(channel == null)
        throw new IllegalStateException("Channel is null.");

    ChannelFuture f = channel.close();
    f.addListener(new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture chf) throws Exception {
            channel = null;
        }
    });

    return f;
}

Now I am trying to test this specific method with unit tests. For that to work, I need a way to mock out the ChannelFuture (ChannelPromise) to control the call of operationComplete method of the listener. I tried it with different approaches. Here is one example test case:

@Test
public void testConnectAfterClose() {
    Channel chMock = mock(Channel.class);
    ChannelPromise promise = new DefaultChannelPromise(chMock);

    when(chMock.close()).thenReturn(promise);
    node.connect(address);
    node.close();
    promise.setSuccess();
    node.connect(address);
}

This test results in a NullPointerException at DefaultPromise.notifyListeners(). Therefore my question is, how could I test code that depends on ChannelFutureListeners?

Upvotes: 1

Views: 1989

Answers (1)

kunerd
kunerd

Reputation: 1076

I found out a way to solve my problem. It works if the mock of the channel (chMock) is replaced with a real channel, for example EmbeddedChannel. After that I use a spy for the channel instead of the mock.

Here is my current solution:

@Test
public void testConnectAfterClose() {
    Channel helper = new EmbeddedChannel(mock(ChannelHandler.class));
    chMock = spy(helper);

    when(chMock.close()).thenReturn(promise);
    node.connect(address);
    node.close();
    promise.setSuccess();
    node.connect(address);
}

@Morfic: Thank you for your comment. It was a nice hint for my current solution.

Upvotes: 2

Related Questions