Модульный тест System.Threading.Timer в .NET - PullRequest
10 голосов
/ 03 марта 2010

Как выполнить модульное тестирование таймера на основе System.Threading.Timer в .NET System.Threading.Timer имеет метод обратного вызова

Ответы [ 4 ]

9 голосов
/ 03 марта 2010

Вы можете протестировать его, не создавая прямой зависимости от System.Threading.Timer. Вместо этого создайте интерфейс ITimer и обертку вокруг System.Threading.Timer, которая его реализует.

Сначала необходимо преобразовать обратный вызов в событие, чтобы его можно было сделать частью интерфейса:

public delegate void TimerEventHandler(object sender, TimerEventArgs e);

public class TimerEventArgs : EventArgs
{
    public TimerEventArgs(object state)
    {
        this.State = state;
    }

    public object State { get; private set; }
}

Затем создайте интерфейс:

public interface ITimer
{
    void Change(TimeSpan dueTime, TimeSpan period);
    event TimerEventHandler Tick;
}

И обертка:

public class ThreadingTimer : ITimer, IDisposable
{
    private Timer timer;

    public ThreadingTimer(object state, TimeSpan dueTime, TimeSpan period)
    {
        timer = new Timer(TimerCallback, state, dueTime, period);
    }

    public void Change(TimeSpan dueTime, TimeSpan period)
    {
        timer.Change(dueTime, period);
    }

    public void Dispose()
    {
        timer.Dispose();
    }

    private void TimerCallback(object state)
    {
        EventHandler tick = Tick;
        if (tick != null)
            tick(this, new TimerEventArgs(state));
    }

    public event TimerEventHandler Tick;
}

Очевидно, вы добавили бы любые перегрузки конструктора и / или Change метода, которые вам нужно использовать из Threading.Timer. Теперь вы можете протестировать все, что угодно, в зависимости от ITimer с фальшивым таймером:

public class FakeTimer : ITimer
{
    private object state;

    public FakeTimer(object state)
    {
        this.state = state;
    }

    public void Change(TimeSpan dueTime, TimeSpan period)
    {
        // Do nothing
    }

    public void RaiseTickEvent()
    {
        EventHandler tick = Tick;
        if (tick != null)
            tick(this, new TimerEventArgs(state));
    }

    public event TimerEventHandler Tick;
}

Всякий раз, когда вы хотите смоделировать тик, просто наберите RaiseTickEvent на подделке.

[TestMethod]
public void Component_should_respond_to_tick
{
    ITimer timer = new FakeTimer(someState);
    MyClass c = new MyClass(timer);
    timer.RaiseTickEvent();
    Assert.AreEqual(true, c.TickOccurred);
}
1 голос
/ 03 марта 2010

Я протестирую его так же, как и любой другой класс, но с короткими временными интервалами, чтобы избежать длительного выполнения модульного теста. Другой подход состоит в том, чтобы протестировать только свой собственный код и использовать фиктивный таймер (например, NMock), но это зависит от дизайна вашего кода. Можете ли вы опубликовать некоторые фрагменты кода?

0 голосов
/ 03 марта 2010

Надеемся, что независимо от того, является ли эта функция большей частью, можно настроить интервал таймера. Вы должны иметь возможность использовать этот интерфейс для ввода короткого интервала, подходящего для модульного тестирования. У меня есть вопрос о значении этого теста: тестируете ли вы интервал (бессмысленно) или что процедура фактически вызывается примерно так часто?

0 голосов
/ 03 марта 2010

Если время просто меняет метод обратного вызова, тогда вам просто нужно проверить правильность этого метода, а не то, как работает системное время.

Кроме того, я рекомендую использовать MultimediaTimer вместо этого - это намного точнее.

...