6

このための単体テストを作成しようとしています:

try (final DatagramChannel channel = helper.createChannel()) {

...

}

私のテストでは、(Mockito を使用して) ヘルパーをモックし、helper.createChannel() にモックされたチャネルを返すように指示します。

このテストは失敗します

java.lang.NullPointerException
at java.nio.channels.spi.AbstractInterruptibleChannel.close(AbstractInterruptibleChannel.java:111)

Java の try-with-resources 機能が、try ブロックの終了時に DatagramChannel の close() メソッドを呼び出すことは理解していますが、モック化された DatagramChannel の close() メソッドを呼び出すべきではありませんか?

デバッガーは、AbstractInterruptibleChannel の closeLock が null であることを通知します。

DatagramChannel をサブクラス化し、close() メソッドをオーバーライドしてから、代わりにサブクラスをモックする必要がありますか? それとも、もっと深刻な方法で何か間違ったことをしていますか (ヘルパー モックがモックを返します)。

よろしく、 フレドリック・イスラエルソン

リクエストに応じてテストコード:

@Mock
private InetAddress peerAddress;
@Mock
private UDPChannelHelper helper;
@Mock
private DatagramChannel channel;

private UDPTransportImpl transport;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    when(helper.createChannel()).thenReturn(channel);
    transport = new UDPTransportImpl(peerAddress, 0, helper);
}

@Test
public void testNormalSubmit() throws Exception {
    transport.submit("Hello");
}

ご覧のとおり、channel.close() の動作は指定していません。close() は void を返すため、私はそうする必要はないと信じています。

4

3 に答える 3

8

DatagramChannelを拡張する実際のクラスをモックしていますAbstractInterruptibleChannel。ただし、これAbstractInterruptibleChannel.closeは最終的なものであり、Mockito は現在、最終的なコードをモックできません。これは、コードに NPE がある理由を説明しています。

所有していない型をモックすることは悪い習慣であると一般に認められていることを思い出してください。人々がそれを行っているのを見たことがありますが、数年後に実際の実装が変更されたとき、彼らは悪い驚きを経験しましたが、モックの動作は変更されなかったため、ライブラリのバージョンを更新したときにすべてが問題ないと誤って考えました。

それでも、正当な理由がある (いくつかの理由がある) ためにこの方法を続けたい場合は、代わりにインターフェイスのモックを返すことができChannelますCloseable。または、対話する必要がある に存在するその他のインターフェイスを使用することもできますDatagramChannel。また、複数のインターフェースが必要な場合は、 を使用してmock(Channel.class, withSetting().extraInterfaces(...))ください。

乾杯、ブライス

于 2013-02-28T13:36:24.517 に答える
1

これを行うべきかどうかは別として、この問題を回避する 1 つの方法は、AbstractInterruptibleChannel モック インスタンス (FileChannel、DatagramChannel など) を「修正」することですcloseLock。危機一髪。

private static void fixChannelMock(AbstractInterruptibleChannel mockFileChannel) throws Exception {
    Field closeLockField = AbstractInterruptibleChannel.class.getDeclaredField("closeLock");
    closeLockField.setAccessible(true);
    closeLockField.set(mockFileChannel, new Object());
}

AbstractInterruptibleChannel の内部実装が変更される可能性があるため、Java のマイナー リリースで上記のコードを修正する必要があることに備えてください。

于 2015-02-10T05:18:59.523 に答える