定期的にアクティビティUIを更新するタイマーとして機能するAndroidアプリの簡単なクラスを作成しています。タイマークラスは、Handler postDelayed()関数を使用してRunnableを実行しています。
コードのタイマーは次のとおりです。
public class MyTimer
{
private MyTimerDelegate _delegate;
private int _seconds = 0;
public MyTimerDelegate delegate() {
return _delegate;
}
public void setDelegate(MyTimerDelegate delegate) {
_delegate = delegate;
}
public int seconds() {
return _seconds;
}
public void setSeconds(int seconds) {
if (seconds < 0)
throw new IllegalArgumentException();
_seconds = seconds;
}
public void start() throws Exception {
if (_delegate == null)
throw new Exception("A delegate has not been set.");
_delegate.MyTimerStartedFromSeconds(this, _seconds);
// Schedule the first timer fire.
final Handler handler = new Handler();
final MyTimer MyTimer = this;
handler.postDelayed(new Runnable() {
@Override
public void run() {
// The timer fired. Decrement seconds.
_seconds -= 1;
// Inform the delegate.
_delegate.MyTimer_countedDownToSeconds(MyTimer, _seconds);
// If there are seconds remaining, schedule the next fire.
// Otherwise, stop the timer.
if (_seconds > 0) {
handler.postDelayed(this, 1000);
} else {
_delegate.MyTimerStopped(MyTimer);
}
}
}, 1000);
}
}
私の質問は次のとおりです。カウントダウン中の各間隔でMyTimerがデリゲートを呼び出していることを確認するために、JUnit 4テストを作成するにはどうすればよいですか?
これが私がこれまでにしたことです:
public void testCountdownCallsDelegate() throws Exception {
class MockMyTimerDelegate implements MyTimerDelegate {
public int callbackCount = 0;
@Override
public void biteTimerStartedFromSeconds(BiteTimer biteTimer, int seconds) {
}
@Override
public void biteTimerStopped(BiteTimer biteTimer) {
}
@Override
public void biteTimer_countedDownToSeconds(BiteTimer biteTimer, int seconds) {
callbackCount++;
}
}
MockMyTimerDelegate delegate = new MockMyTimerDelegate();
MyTimer timer = new MyTimer();
timer.setDelegate(delegate);
timer.setSeconds(1);
timer.start();
// Need some way to wait here and allow the timer to call its delegate...
assertEquals("The timer should have called the delegate when counting down.", 1, delegate.callbackCount);
}
明らかに、Thread.sleep()呼び出しでスレッドをブロックすることはできません。何か案は?
見つかった解決策
この解決策はうまくいくようです。他の人の役に立つ場合に備えて、ここに投稿します。方法が見つかれば改善してください。
public void testMyTimerDelegateIsCalledForEachSecondDuringCountdown() throws Exception {
// An object to sync our threads with.
Object syncLock = new Object();
// This thread class will perform the actual test.
class TimerThread extends Thread
{
Object _syncLock;
TimerThread(Object syncLock) {
_syncLock = syncLock;
}
@Override
public void run() {
// Since MyTimer is calling Handler postDelayed(), we need a Looper.
Looper.prepare();
// myTimer was instantiated in setUp()
myTimer.setDelegate(new MockMyTimerDelegate() {
@Override
public void myTimer_countedDownToSeconds(MyTimer myTimer, int seconds) {
countdownToSecondsCallCount++;
if (countdownToSecondsCallCount >= 3) {
synchronized (_syncLock) {
// The test is complete. Now the parent thread can continue and assert the results.
_syncLock.notify();
}
}
}
});
myTimer.setSeconds(3);
try {
myTimer.start();
Looper.loop();
} catch (Exception e) {
}
}
}
// Run the test on its own thread and wait for it to finish.
TimerThread t = new TimerThread(syncLock);
t.start();
synchronized (syncLock) {
// Wait more time than should be needed, but timeout in case of failure.
syncLock.wait(5000);
}
assertEquals("MyTimerDelegate should have been called 3 times during three second countdown.", 3, ((MockMyTimerDelegate) myTimer.delegate()).countdownToSecondsCallCount);
}