11

メソッドを実行するために、特定の間隔でオブザーバーを呼び出すメソッドのテストを書きたいと思います。timer-object は独自のスレッドで実行されます。

テストするタイマーの方法
private long waitTime;

public Metronome(int bpm) {
    this.bpm = bpm;
    this.waitTime = calculateWaitTime();
    this.running = false;
}

public void run() {
    long startTime = 0, estimatedTime = 0, threadSleepTime = 0;

    running = true;

    while (running) {
        startTime = System.nanoTime();

        tick();// notify observers here

        estimatedTime = System.nanoTime() - startTime;
        threadSleepTime = waitTime -estimatedTime;
        threadSleepTime = threadSleepTime < 0 ? 0 : threadSleepTime;

        try {
            Thread.sleep(threadSleepTime / 1000000l);

        } catch (InterruptedException e) {
                // sth went wrong
        }
    }
}
私のテストクラスからのスニペット
private int ticks;
private long startTime;
private long stopTime;

@Test
public void tickTest(){
    metronome.setBpm(600);
    startTime = System.nanoTime();
    metronome.run();
    long duration = stopTime - startTime;
    long lowThreshold  =  800000000;
    long highThreshold =  900000000;
    System.out.println(duration);
    assertTrue(lowThreshold < duration); 
    assertTrue(duration <= highThreshold);      
}

@Override
public void update(Observable o, Object arg) {
    ticks ++;       
    if(ticks == 10){
        metronome.stop();
        stopTime = System.nanoTime();
    }
}

現在、テストクラスは問題のオブジェクトのオブザーバーとして登録されているため、 tick() が実行された回数を数えることができます。テストは実行前後の時間を測定しますが、このように動作をテストするのは面倒です。

テストを改善するための提案はありますか?

4

4 に答える 4

2

場合によっては、テストの必要がないほど十分に単純な標準ライブラリの何かを使用することで解決できます。SchedulerExecuterServiceここでテストされている自家製タイマーを交換するためのトリックを行うと思います。ライブラリ コードのバグに噛まれることはほとんどありませんが、バグは存在することに注意してください。

ただし、一般的には、ヘルパー クラスを作成するか、モッキング フレームワーク (Mockito) を使用して、「ティック」をカウントするなどの簡単なことを行っても問題ないと思います。

PSThread.sleep(threadSleepTime / 1000000l)TimeUnit.NANOSECONDS.sleep(threadSleepTime)... に置き換えることができます。これにより、一部のロジックがコードから標準ライブラリに移動されます。

于 2012-09-24T23:03:18.023 に答える
2

あなたのコメントに基づいて、コードを変更しました。テストクラスにオブザーバー インターフェイスを実装する代わりに、タイマーに登録するインターフェイスを実装するプライベート クラスを作成しました。

あなたの時間と考えをありがとう。

コードは次のようになります。

改訂されたテストコード
@Test(timeout = 2000)
public void tickTest(){     
    long lowThreshold  = 400000000;
    long highThreshold = 600000000;

    TickCounter counter = new TickCounter();
    metronome.addObserver(counter);
    metronome.setBpm(600);

    startTime = System.nanoTime();
    metronome.run();
    long duration = System.nanoTime() - startTime;


    assertTrue(lowThreshold <= duration);
    assertTrue(duration <= highThreshold);      
}

private class TickCounter implements Observer{
    private int ticks;

    public TickCounter(){
        ticks = 0;
    }

    @Override
    public void update(Observable o, Object arg) {
        ticks++;        
        if(ticks == 5){
            metronome.stop();
        }
    }       
}
私の改訂されたタイマーからのスニペット
private long expectedTime; // calculated when bpm of timer is set

@Override
public void run() {
    long startTime = 0, elapsedTime = 0, threadSleepTime = 0;

    running = true;

    while (running) {
        startTime = System.nanoTime();

        tick();

        elapsedTime     = System.nanoTime() - startTime;

        threadSleepTime = expectedTime - elapsedTime;
        threadSleepTime = threadSleepTime < 0 ? 0 : threadSleepTime;

        try { TimeUnit.NANOSECONDS.sleep(threadSleepTime); } catch (Exception e) { }
    }
}

私の最大の問題は、JUnit テストケースにオブザーバー インターフェイスを実装したことです。そこで、ティックが実行された回数を具体的にカウントするプライベートオブザーバーを作成しました。次に、カウンターがタイマーを停止します。

testmethod はタイミングを測定し、必要な時間が定義された制限の間のどこかにあることを主張します。

于 2012-09-25T10:15:14.660 に答える
1

それはあなたが時間をどれだけ正確に測定する必要があるかに依存します。

「ぎこちない」と感じたら、それは測定が十分に正確かどうかわからないからですか?OSがオーバーヘッドの邪魔になるのではないかと心配ですか?

その場合、コードをテストするため、または場合によっては発火イベントのトリガーを提供するために、正確なソース(GPS、アトミック標準など)に同期する外部タイミングボードが必要になる場合があります。

于 2012-09-24T22:48:13.143 に答える
1

これを試して。また、あなたが期待している時間も必要です。予想される時間は、タイマーが 1 秒あたりに必要とする回数1000000000/nです。ntick()

public void run(){
    long time = System.nanotime();
    long elapsedTime = 0;
    // Hope you need to tick 30 times per second
    long expectedTime = 1000000000/30;
    long waitTime = 0;
    while (running){
        tick();
        elapsedTime = System.nanotime()-time;
        waitTime = expectedTime-elapsedTime();
        if (waitTime>0){
            try { Thread.sleep(waitTime) } catch (Exception e){}
        }
        time = System.nanotime();
    }
}
于 2012-09-25T00:36:26.310 に答える