0

TFS2012ビルドサーバーでのチェックイン中に実行されるプロジェクト用の単体テストも多数あります。ローカルでは期待どおりに動作しますが、TFSでタイマーを使用するユニットテストで奇妙な動作が発生することがあります。最後に、その動作を分離するためのクラスとテストを作成しました。

クラス:

public class TestTimerOnServer    
{    
    Timer _MyTimer = new Timer(100);    
    int _CountsToDo = 100;    
    public int TimerElapsedCounter = 0;

    public TestTimerOnServer()    
    {    
        _MyTimer.Elapsed += _MyTimer_Elapsed;    
    }

    public void StartCounting(int argNumberOfCounts, int argIntervalInMs)    
    {    
        _MyTimer.Stop();    
        _MyTimer.Interval = argIntervalInMs;    
        TimerElapsedCounter = 0;    
        _CountsToDo = argNumberOfCounts;    
        _MyTimer.Start();    
    }

    void _MyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)    
    {    
        if (_CountsToDo > TimerElapsedCounter)    
            TimerElapsedCounter++;    
        else    
            _MyTimer.Stop();    
    }    
}

それに対して実行されているテスト:

private void TestTimerServerBehaviour()   
{   
   TestTimerOnServer ttos = new TestTimerOnServer();   
   ttos.StartCounting(10, 100); // should lead 1000 ms

   // we wait 1100 MS   
   Thread.Sleep(1100);

   Assert.AreEqual(ttos.TimerElapsedCounter, 10,"We should have 10 
   samples, but only " + ttos.TimerElapsedCounter + " have been generated.!"); 

   ttos.StartCounting(50, 100); // should lead 5000 ms

   // we wait 6000 MS   
   Thread.Sleep(6000);

   Assert.AreEqual(ttos.TimerElapsedCounter, 50, "We should have 50 
   samples, but only " + ttos.TimerElapsedCounter + " have been generated.!");   
}

ほとんどの場合、このテストは合格しますが、TFSで失敗することもあります。たとえば、50回ではなく2回だけイベントを発生させます。問題は、ここで一般的な単体テストの設計上の欠陥が発生するのか、それともTFSビルドサービスでテストを実行する際に問題が見つかるのかということです。

編集: TFSはVMで実行されています-これが問題の原因である可能性がありますか?

EDIT2-最終調査結果 問題は明らかにTesting-ContextとVMwareの組み合わせでした。@allenによって投稿されたコードを使用して小さなアプリケーションを作成しました。同じコードを使用したテストと、CPUに負荷をかける別のコードを使用しました。

void CPULoader()
{
    var action = new Action(() => { while (true);});

    Parallel.Invoke(action, action, action, action, action, action, action, action); 
}

非常に原始的ですが効率的です。

アプリケーションとCPUローダーを実行している私のハードウェアマシンでは、タイマーイベントが少し遅れて発生します(たとえば、1000ではなく1100ミリ秒)。これまでのところ、Win7はリアルタイムシステムではありません。

VMwareでは、いくつかの組み合わせにより、最大5000ミリ秒の遅延が発生します。1秒かかるはずです...-もちろん、はるかに悪いですが、それでもイベントは発生します。

本当の楽しみは、テストを実行し(その目的のためにコードを無限ループにパックしました)、CPUローダーを起動することから始まります。CPUのロードを停止し、テストの前にイベントが発生しなくなるまで、システム全体が非常に遅くなります。

これが誰かにいくつかのヒントを与えることができることを願っています-タイマー抽象化を使用し、単体テスト中にタイミング動作をモックすることによってテストを修正しました。副作用として、テストは今より速く実行されます:)

4

2 に答える 2

1

私の疑いはVMにあります。VMを使用すると、時間同期に関連する問題が発生し、タイミング関連の機能で問題が発生する可能性があります。これを確認する1つの方法は、単純なコードを記述して同じVMで実行することです。

Stopwatch watch = new Stopwatch();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 30*60 * 1000;
timer.Elapsed += timer_Elapsed;
watch.Start();
timer.Start();

static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    watch.Stop();
    Console.WriteLine("Stopwatch value - {0}", watch.Elapsed);
    watch.Restart();
}

別の例は、stackoverflowでもここにありますSystem.Diagnostics.Stopwatchは、Elapsed...プロパティで負の数を返します

これを引き起こす可能性のある要因のいくつかは、a)VMでの時間同期サービスの無効化b)ホスト上のリソースの不足です。VMが多すぎます

私の提案は、このVM専用のより多くのリソースを備えたホスト上に新しいVMをセットアップすることです。

于 2013-02-27T18:57:38.197 に答える
1

システムコールsleepや親戚はしばしばシグナルハンドラーと相互作用し、彼らの睡眠を早期に中止します。この現象はUnix sleep(3)関数で最もよく文書化されていますが、APIにも当てはまると思います。睡眠後の現在時刻を確認して、短い睡眠を防ぐ必要があります。

一般に、タイマーユニットテストをシステムクロックから可能な限り切り離す必要があります。キューベースのタイマーと外部から呼び出すことができるハートビート関数で作業したときは非常に良い経験がありましたが、関数の呼び出しsleepとタイムフェッチ関数をダミーアウトして、実際の関数を呼び出さずにテストできるはずです。

于 2013-02-26T10:48:26.183 に答える