45

タイプがのプライベートメンバーを持つクラスがありSystem.Windows.Forms.Timerます。タイマーが作動するたびに呼び出されるプライベートメソッドもあります。

  1. メソッドをテストする価値はありますか?(プライベートなので)
  2. どうすればテストできますか?(テストしたいクラスをテストクラスに継承させることができることはわかっています...)
  3. タイマーをあざける必要がありますか?内部タイマーを使用するクラスをテストする必要がある場合、テストが完了するまでに長い時間がかかる可能性があるためです。

編集:

実際、このメソッドはタイミングに依存しています。コードは次のとおりです。

private void alertTick(object sender, EventArgs e) {
    if (getRemainingTime().Seconds <= 0) {
        Display.execute(Name, WarningState.Ending, null);
        AlertTimer.Stop();
    }
    else {
        var warning = _warnings.First(x => x == getRemainingTime());

        if (warning.TotalSeconds > 0)
            Display.execute(Name, WarningState.Running, warning);
    }
}

ご覧のとおり、タイマーが実行されている場合、タイマーはDisplay.execute()終了時(残り時間が0のとき)とは異なるパラメーターで呼び出します。それはデザインの問題でしょうか?

4

2 に答える 2

46
  1. メソッド(プライベートまたはパブリック)をテストしていません-クラスの動作を検証しています。また、一部の動作を検証していない場合は、それが実装されたとは言えません。この動作を呼び出す方法はいくつかあります。クラスのパブリックインターフェイス、または依存関係にあるイベントです。また、動作の呼び出しによってパブリックインターフェイスが到達するものが変更される必要はなく、依存関係との相互作用も重要です。
  2. 以下の例を参照してください-このような「隠された」動作をテストする方法を示しています。
  3. 以下の例を参照してください-責任を分割し、依存性を注入し、それらをモックする方法を示しています。

実際、クラスにはあまりにも多くの責任があります。1つはタスクをスケジュールし、もう1つはアクションを実行します。クラスを1つの責任を持つ2つの別々のクラスに分割してみてください。

したがって、スケジューリングはスケジューラーに行きます:)スケジューラーのAPIは次のようになります:

public interface IScheduler
{
    event EventHandler<SchedulerEventArgs> Alarm;
    void Start();
    void Stop();
}

今のところスケジューラーを忘れてください。2番目のクラスに戻って実装します。これにより、いくつかの警告が表示されます。最初にテストに行きましょう(Moqを使用):

[Test]
public void ShouldStopDisplayingWarningsWhenTimeIsOut()
{
    Mock<IDisplay> display = new Mock<IDisplay>();
    Mock<IScheduler> scheduler = new Mock<IScheduler>();                      

    Foo foo = new Foo("Bar", scheduler.Object, display.Object);
    scheduler.Raise(s => s.Alarm += null, new SchedulerEventArgs(0));

    display.Verify(d => d.Execute("Bar", WarningState.Ending, null));
    scheduler.Verify(s => s.Stop());
}

実装の記述:

public class Foo
{
    private readonly IScheduler _scheduler;
    private readonly IDisplay _display;
    private readonly string _name;

    public Foo(string name, IScheduler scheduler, IDisplay display)
    {
        _name = name;
        _display = display;
        _scheduler = scheduler;
        _scheduler.Alarm += Scheduler_Alarm;
        _scheduler.Start();
    }

    private void Scheduler_Alarm(object sender, SchedulerEventArgs e)
    {
        _display.Execute(_name, WarningState.Ending, null);
        _scheduler.Stop();
    }
}

テストに合格します。別のものを書く:

[Test]
public void ShouldNotStopDisplayingWarningsWhenTimeRemains()
{
    Mock<IDisplay> display = new Mock<IDisplay>(MockBehavior.Strict);
    Mock<IScheduler> scheduler = new Mock<IScheduler>(MockBehavior.Strict);
    scheduler.Setup(s => s.Start());

    Foo foo = new Foo("Bar", scheduler.Object, display.Object);
    scheduler.Raise(s => s.Alarm += null, new SchedulerEventArgs(1));
}

テストに失敗しました。ああ、残り時間の条件が必要です:

private void Scheduler_Alarm(object sender, SchedulerEventArgs e)
{
    if (e.RemainingTime > 0)
        return;

    _display.Execute(_name, WarningState.Ending, null);
    _scheduler.Stop();
}

クラスのテストを引き続き作成できます。このテストは、スケジューラーアラートの処理と、表示されているいくつかの警告の実行を担当します。終了したら、ISchedulerインターフェイスの実装を記述できます。System.Windows.Forms.TimerまたはSystem.ThreadingTimer、あるいはその他の方法で、スケジューリングをどのように実装するかは重要ではありません。

于 2012-07-15T23:10:58.927 に答える
27

メソッドをテストする価値はありますか?(プライベートなので)

あなたの目的は、あなたのコードが機能するかどうかを決定することです。プライベートメソッドであっても、パブリックインターフェイスから到達できる出力を生成する必要があります。クラスが機能しているかどうかをユーザーが認識できるようにクラスを設計する必要があります。

また、単体テストを行っている場合、タイマーをモックできる場合は、タイマーのElapsedイベントに割り当てられたコールバックに到達できます。

どうすればテストできますか?(テストしたいクラスをテストクラスに継承させることができることはわかっています...)

ここでアダプタクラスを使用できます。Timerクラスは抽象化を提供しないため、最初に抽象化を定義する必要があります。

public interface ITimer
{
    void Start();
    void Stop();
    double Interval { get; set; }
    event ElapsedEventHandler Elapsed;
    //and other members you need
}

次に、Timerクラスから継承するだけで、このインターフェイスをアダプタクラスに実装できます。

public class TimerAdaper : Timer, ITimer { }

テストでモックできるように、コンストラクターに(またはプロパティとして)抽象化を挿入する必要があります。

public class MyClass
{
    private readonly ITimer _timer;

    public MyClass(ITimer timer)
    {
        _timer = timer
    }
}

タイマーをあざける必要がありますか?内部タイマーを使用するクラスをテストする必要がある場合、テストが完了するまでに長い時間がかかる可能性があるためです。

もちろん、あなたはあなたのタイマーをあざけるべきです。単体テストはシステム時間に依存することはできません。モックでイベントを発生させ、コードがどのように動作するかを確認する必要があります。

于 2012-07-15T21:52:50.987 に答える