1

定期的にアクティビティ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);
}
4

0 に答える 0