Как к модульному тесту таймер на основе Системы. Поточная обработка. Таймер в.NET Система. Поточная обработка. Таймер имеет метод обратного вызова
Вы можете протестировать его, не создавая прямую зависимость от 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);
}
Я буду тестировать его так же, как и любой другой класс, но с короткими временными интервалами, чтобы избежать длительного выполнения модульного теста. Другой подход - тестировать только собственный код и использовать имитатор таймера (например, NMock), но это зависит от того, как устроен ваш код. Не могли бы вы выложить несколько фрагментов кода?
.Надеюсь, то, частью чего является эта функция, позволяет настраивать интервал таймера. Вы должны быть в состоянии использовать этот интерфейс для введения короткого интервала, подходящего для модульного тестирования. Правда, у меня возникает вопрос о ценности этого теста: Тестируете ли вы интервал (бессмысленно) или то, что рутина действительно вызывается примерно каждый раз?
.Если время просто изменяет метод обратного вызова, то вам просто нужно проверить корректность этого метода, а не то, как работает системное время.
Кроме того, я рекомендую вместо этого использовать MultimediaTimer - он намного точнее.