山崎です.
スレッド間の通信機構の単体テストをどう書くか, 知恵を貸してください.
例えば下記のようなメッセージキューを実装するとします. 基本的には, 二つ
スレッドがあって, 一方が send, もう一方が receive を行う使い方をすると
します. そして, send が S1, S2, receive が R1, R2 という処理で構成され
ているとします.
public class MessageQueue {
public void send(Object message) { S1; S2; }
public Object receive() { R1; R2; }
}
テストしたい内容は, 例えばスレッド1(以下 T1 と書きます)が S1 を実行し,
S2 を実行する直前に, 別のスレッド T2 が R1 を実行した直後, ブロックす
ることを確認する, といった感じです.
僕が思いついた方法を説明します. まず S1 と S2, R1 と R2 の間にフックと
なるメソッド呼び出しをあらかじめ定義しておきます.
public class MessageQueue {
public void send(Object message) { S1; sendHook(); S2; }
public Object receive() { R1; receiveHook(); R2; }
protected void sendHook() {}
protected void receiveHook() {}
}
ちょっと長いですが, テストプログラムはこんな感じ
public class MessageQueueTest extends TestCase {
public MessageQueueTest(String arg0) {
super(arg0);
}
class MessageQueueSub1 extends MessageQueue {
volatile boolean flag = false;
final Object breakPoint = new Object();
protected void hookSend() {
synchronized(breakPoint) {
try {
breakPoint.wait();
} catch(InterruptedException e) {}
}
}
protected void hookReceive() {
flag = true;
}
}
class ThreadSub1 extends Thread {
public Object result;
public MessageQueue queue;
public ThreadSub1(MessageQueue queue) {
this.queue = queue;
}
public void run() {
result = queue.receive();
}
}
public void testSub1() {
final MessageQueueSub1 queue = new MessageQueueSub1();
final Object value = new Object();
Thread t1 = new Thread() {
public void run() {
queue.send(value);
}
};
ThreadSub1 t2 = new ThreadSub1(queue);
t1.start();
t2.start();
Thread.yield();
assertFalse(queue.flag);
}
}
MessageQueueSub1 はフックを定義していて, send の時は停止して receive
の時には通過したというフラグを立てます. ThreadSub1 は receive の返値を
格納しておくスレッドです. testSub1 がテストメソッド本体で, queue を用
意して t1, t2 を走らせて, t2 がフラグを立てないことを確認します.
この方法で気に入らない点は以下の通りです.
1. あらかじめフックを入れるのがいまいち.
2. フラグで間接的に調べるだけでなく, t2 が synchronized, wait 等で停止
しているのかどうかを確認したい.
何かいいアイデアがあったら, よろしくお願いします.
山崎 進 --- yamazaki@....jp
福岡県産業・科学技術振興財団
福岡知的クラスター研究所