Модульное тестирование в C # - Thread.Sleep (x) - Как проверить системные часы - PullRequest
11 голосов
/ 03 августа 2010

Я должен протестировать метод, который выполняет определенное количество работы после интервала.

while (running)
{
    ...
    // Work
    ...
    Thread.Sleep(Interval);
}

Интервал передается в качестве параметра классу, так что я могу просто передать 0 или 1, но меня интересовало, как смоделировать системные часы, если это не так.

В моем тесте я хотел бы иметь возможность просто установить время вперед с помощью TimeSpan Интервал и получить пробуждение потока.

Я никогда раньше не писал тестов для кода, который воздействует на исполняющий поток, и я уверен, что есть некоторые подводные камни, которых следует избегать - пожалуйста, не стесняйтесь уточнять, какой подход вы используете.

Спасибо!

Ответы [ 2 ]

16 голосов
/ 03 августа 2010

Если вы не хотите проверять тот факт, что поток на самом деле спит, более простой подход (и тот, который возможен) заключается в использовании ISleepService.Затем вы можете смоделировать это, а затем не спать в ваших тестах, но иметь реализацию, которая вызывает Thread.Sleep в вашем рабочем коде.

ISleepService sleepService = Container.Resolve<ISleepService>();

..

while (running)
{
    ...
    // Work
    ...
    sleepService.Sleep(Interval);
}

Пример с использованием Moq:

    public interface ISleepService
    {
        void Sleep(int interval);
    }

    [Test]
    public void Test()
    {
        const int Interval = 1000;

        Mock<ISleepService> sleepService = new Mock<ISleepService>();
        sleepService.Setup(s => s.Sleep(It.IsAny<int>()));
        _container.RegisterInstance(sleepService.Object);

        SomeClass someClass = _container.Resolve<SomeClass>();
        someClass.DoSomething(interval: Interval);

        //Do some asserting.

        //Optionally assert that sleep service was called
        sleepService.Verify(s => s.Sleep(Interval));
    }

    private class SomeClass
    {
        private readonly ISleepService _sleepService;

        public SomeClass(IUnityContainer container)
        {
            _sleepService = container.Resolve<ISleepService>();
        }

        public void DoSomething(int interval)
        {
            while (true)
            {
                _sleepService.Sleep(interval);
                break;
            }
        }
    }

Обновление

В заметке о проекте \ обслуживании, если больно изменить конструктор SomeClass или добавить точки внедрения зависимости для пользователя класса, тогдаздесь может помочь шаблон типа локатора службы, например:

private class SomeClass
{
    private readonly ISleepService _sleepService;

    public SomeClass()
    {
        _sleepService = ServiceLocator.Container.Resolve<ISleepService>();
    }

    public void DoSomething(int interval)
    {
        while (true)
        {
            _sleepService.Sleep(interval);
            break;
        }
    }
}
2 голосов
/ 03 августа 2010

Вы не можете по-настоящему насмехаться над системными часами.

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

Я бы создал одноэлементный сервис, который мог бы быть внедрен в приложение, когда оно тестируется.Служба Singleton должна включать методы, позволяющие некоторому внешнему абоненту (например, модульному тесту) отменить операцию сна.

В качестве альтернативы, вы можете использовать Mutex или WaitHandle объекта * 1012.* метод с параметром тайм-аута.Таким образом, вы можете запустить мьютекс, чтобы отменить «сон» или дать ему время ожидания:

public WaitHandle CancellableSleep = new WaitHandle(); // publicly available

// in your code under test use this instead of Thread.Sleep()...
while( running ) {
    // .. work ..
    CancellableSleep.WaitOne( Interval ); // suspends thread for Interval timeout
}


// external code can cancel the sleep by doing:
CancellableSleep.Set(); // trigger the handle...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...