※一度書いた内容が不完全だったので書き直してます
以下のようなコードで、SocketChannelをモック化して、catch IOExceptionを確認したいと思います。
モックライブラリは「mockito」を使います。
public class App {
public void method(SocketChannel channel) throws IOException {
if (channel.isOpen()) {
try {
channel.close();
} catch (IOException e) {
// do anything..
}
}
}
}
SocketChannelをモックオブジェクトとして、isOpenとcloseの振る舞いを変えたいところですが、finalメソッドなのでモック化できません。
そこでPowerMockを組み合わせます。
Mavenを使っている場合は、pom.xmlのdependenciesに以下を追加します。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.4</version>
<scope>test</scope>
</dependency>
PowerMockの使い方は、https://code.google.com/p/powermock/wiki/MockitoUsage13 を参照してください。
テストコードは以下のようになります。
モックインスタンスの生成にPowerMockito#mock(Class)
を使う以外は、普通にmockitoで行うモックの設定方法と同じです(*1)。
@RunWith(PowerMockRunner.class)
@PrepareForTest({App.class, SocketChannel.class})
public class AppTest {
@Test
public void testMethod() throws Exception {
App target = new App();
SocketChannel channel = PowerMockito.mock(SocketChannel.class);
Mockito.doThrow(new IOException()).when(channel).close();
Mockito.when(channel.isOpen()).thenReturn(true);
try {
target.method(channel);
fail();
} catch (Exception e) {
verify(channel, times(1)).close();
}
}
@PrepareForTestにはテスト対象のクラスも指定します(このサンプルの場合はApp.class)。含めないとモックオブジェクトを渡してもモックの動きをしてくれません。
最初、モック対象のクラスだけを含めればよいのかと思っていたら違いました。
*1 「PowerMockito.mock(SocketChannel.class)」を「Mockito.mock(SocketChannel.class)」に変えると以下のように実行時にエラーとなります。
モック化されていないメソッドが呼び出されています。
java.lang.NullPointerException at java.nio.channels.spi.AbstractInterruptibleChannel.close(AbstractInterruptibleChannel.java:111) at sample.AppTest.testA(AppTest.java:38)