Как разработать тест класса StopWatch в первую очередь? - PullRequest
0 голосов
/ 22 августа 2010

Я сейчас пытаюсь реализовать класс StopWatch. Интерфейс примерно такой:

interface IStopWatch {
    void Run();
    void Stop();
    int SecondsElapsed { get; }
    int MinutesElapsed { get; }
}

В основном мое приложение должно будет использовать StopWatch, но для целей тестирования было бы неплохо иметь способ искусственного изменения результатов StopWatch es, поэтому я делаю весь свой код ссылка IStopWatch вместо .NET System.Stopwatch.

Поскольку я пытаюсь разработать этот Test-First, мне придется создавать код для моего StopWatch класса только после написания его тестов. Я уже понял, что тесты, которые я собираюсь сделать, не будут модульными, поскольку я использую класс System.Stopwatch .NET для внутреннего использования.

Итак, по моему заданию, единственное, что я могу сейчас сделать, - это тесты, которые выглядят следующим образом:

[TestMethod]
public void Right_After_Calling_Run_Elapsed_Minutes_Equals_Zero() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Assert.AreEqual<int>(0, stopWatch.ElapsedMinutes);
}

[TestMethod]
public void One_Second_After_Run_Elapsed_Seconds_Equals_One() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Thread.Sleep(1000 + 10);
    Assert.AreEqual<int>(1, stopWatch.ElapsedSeconds);
}

[TestMethod]
public void Sixty_Seconds_After_Run_Elapsed_Minutes_Equals_One() {
    IStopWatch stopWatch = new StopWatch();
    stopWatch.Run();
    Thread.Sleep(60 * 1000 + 1000);
    Assert.AreEqual<int>(1, stopWatch.ElapsedMinutes);            
}

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

Спасибо

Редактировать

Итак, я последовал советам Quinn351 и Sjoerd и написал нечто, использующее DateTimes вместо класса секундомера .NET:

public class MyStopWatch : IMyStopWatch {
    private DateTime? firstDateTime = null;
    private DateTime? secondDateTime = null;
    private bool isRunning = false;

    public void Start() {
        isRunning = true;
        firstDateTime = DateTime.Now;
    }

    public void Stop() {
        isRunning = false;
        secondDateTime = DateTime.Now;
    }

    public void Reset() {
        firstDateTime = null;
        secondDateTime = null;
        isRunning = false;
    }

    public TimeSpan GetTimeElapsed() {
        return secondDateTime.Value.Subtract(firstDateTime.Value);
    }
}

Это позволяет мне делать другие реализации, которые имеют getter / setters для обеих дат, чтобы я мог заставить GetTimeElapsed () возвращать все, что я хочу.

Ответы [ 4 ]

3 голосов
/ 22 августа 2010

Зачем "искусственно модифицировать результаты StopWatches" ?!Какова вся цель тестирования, если вы собираетесь изменить свои результаты?

Что касается тестирования, вы должны также протестировать метод stop и проверить, является ли количество секунд примерно в 60 раз больше количества минут.

Класс, который вы пишете, может также использовать StopWatch для внутреннего использования, а затем изменять результаты по запросу (тогда вы всегда можете вернуться к исходным результатам).

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

2 голосов
/ 22 августа 2010

Ваш класс секундомера, вероятно, откуда-то получает дату и время. Сделать объект, который возвращает текущую дату. Это был бы очень простой класс. При тестировании вместо этого передайте объект mock , который возвращает фиктивные дату и время. Таким образом, вы можете притворяться в своем тесте, как будто прошло много секунд.

class DateTime {
    public Date getDate() {
        return System.DateTime.Now();
    }
}

class MockDateTime {
    public Date getDate() {
        return this.fakeDate;
    }
}

class StopwatchTest {
    public void GoneInSixtySeconds() {
        MockDateTime d = new MockDateTime();
        d.fakeDate = '2010-01-01 12:00:00';
        Stopwatch s = new Stopwatch();
        s.Run();
        d.fakeDate = '2010-01-01 12:01:00';
        s.Stop();
        assertEquals(60, s.ElapsedSeconds);
    }
}
1 голос
/ 22 августа 2010

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

C # Секундомер показывает неправильное время

Так что использование Thread.Sleep не даст вам точного времени. Вам бы лучше реализовать собственную версию секундомера, используя DateTime.Now

0 голосов
/ 01 марта 2017

В дополнение к редактированию выше: не используйте этот метод для определения истекшего времени! Не работает, когда:

  • Элемент списка
  • часы или часовой пояс устанавливаются
  • летнее время начинается или заканчивается
  • часы ненадежны (например, внутри виртуальной машины)

... и, возможно, ряд других состояний.

...