Yのはてな

2007-07-30 JavaJava

EasyMockでSocketクラスのモックを作る

外的環境に依存するクラスの代表であるSocketクラスを、ネットワーク接続が切れた環境で気軽にユニットテストしたかったので調べてみた。


結論からいうと、題の通りの方法で実現することができた。


Socketクラスならば継承してモック作れるじゃん。と、最初思ったのだが、モッククラスを作成すると以下のメリットが享受できる。

  • 指定していないメソッド呼び出しを例外扱いしてくれるので、テスト対象の予期しないメソッド呼び出しを検出できる。
  • 複数のクラスにまたがって、メソッド呼び出しの順番を指定できるので、ソケットのエミュレーションを実現しやすい。
  • テストでしか使わないクラスのコードを書かないので楽。

これはEasyMockの仕様なのかも知れないが、

というデメリットもある。(解決方法を知らないだけかもしらないが)


DIコンテナと組み合わせると、ソケットに依存する全てのクラスが楽にユニットテストできるので一考の価値あり。


import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createControl;
import static org.junit.Assert.*;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import org.easymock.classextension.IMocksControl;
import org.junit.Before;
import org.junit.Test;

public class SocketTest {

	byte[] data = "test data".getBytes();

	Socket socket;
	IMocksControl control;

	@Before
	public void ソケット生成() throws Exception{
		control = createControl();

		InputStream in = control.createMock(InputStream.class);
		OutputStream out = control.createMock(OutputStream.class);
		socket = control.createMock(Socket.class);

		// InputStreamとOutputStreamはモックを返す。
		expect(socket.getInputStream()).andReturn(in);
		expect(socket.getOutputStream()).andReturn(out);

		// ここより下のメソッド呼び出しは順番を強制する。
		control.checkOrder(true);

		out.write(data);
		socket.shutdownOutput();
		expect(in.read()).andReturn(255);
		expect(in.read()).andReturn(0);
		socket.close();

		// 登録完了。
		control.replay();
	}

	@Test
	public void ソケットテスト() throws Exception{
		// この下2行分はメソッド呼び出し順番を強制されない。
		OutputStream out = socket.getOutputStream();
		InputStream in = socket.getInputStream();

		// 順番通りにメソッドを呼び出す必要がある。
		out.write(data);
		socket.shutdownOutput();
		assertEquals(255, in.read());
		assertEquals(0, in.read());
		socket.close();

		// モックが登録通りに呼び出されたか確認する。
		control.verify();
	}
}

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/jbking/20070730/p1