Поблочное тестирование C# - поток. Сон (x) - как дразнить системные часы

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

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

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

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

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

Спасибо!

11
задан gav 3 August 2010 в 15:52
поделиться

2 ответа

Если вы не хотите проверять тот факт, что поток действительно спит, то более простым подходом (и возможным) является наличие 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", или добавлять точки Dependency Injection для пользователя класса, то здесь может помочь паттерн типа локатора сервиса, например:

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;
        }
    }
}
17
ответ дан 3 December 2019 в 06:19
поделиться

Вы не можете издеваться над системными часами.

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

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

В качестве альтернативы вы можете использовать метод WaitOne () объекта Mutex или WaitHandle , у которого есть параметр тайм-аута. Таким образом, вы можете запустить мьютекс для отмены "сна" или дать ему время ожидания:

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...
2
ответ дан 3 December 2019 в 06:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: