Подтвердить что ты не робот

Обучение TDD с помощью простого примера

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

Спецификация (упрощенная версия) для приложения выглядит следующим образом:

Ему нужно взять у пользователя местоположение CSV файла, расположение шаблона mailmerge документа Word и место вывода.

Затем приложение будет читать файл csv и для каждой строки, объединить данные с шаблоном слова и вывести их в указанную папку.

Просто, чтобы быть ясным, я не спрашиваю, как я буду кодировать такое приложение, поскольку я уверен, что знаю, как это сделать, если я только пошел вперед и начал. Но если бы я захотел сделать это с помощью TDD, некоторые рекомендации по написанию тестов были бы оценены, поскольку я предполагаю, что не хочу тестировать чтение реального CSV файла или тестировать сторонний компонент, который выполняет слияние или конвертирует в pdf.

Я думаю, что просто какое-то общее руководство TDD будет большой помощью!

4b9b3361

Ответ 1

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

  • Пользователь предоставляет нулевое местоположение файла csv (выбрасывает ArgumentNullException).

  • Пользователь предоставляет пустое место в каталоге csv (выбрасывает ArgumentException).

  • Файл csv, указанный пользователем, не существует (что бы вы ни считали подходящим).

Затем напишите тест для каждого из этих сценариев и убедитесь, что он не работает. Затем напишите достаточно кода, чтобы пройти тест. Это довольно легко для некоторых из этих условий, потому что код, который делает ваш тестовый проход, часто является окончательным кодом:

public class Merger { 
    public void Merge(string csvPath, string templatePath, string outputPath) {
        if (csvPath == null) { throw new ArgumentNullException("csvPath"); }
    }
}

После этого перейдите в стандартные сценарии:

  • Указанный файл csv имеет одну строку (объединение должно быть вызвано один раз, вывод написан в ожидаемое место).

  • Указанный файл csv имеет две строки (слияние должно вызываться дважды, вывод записывается в ожидаемое местоположение).

  • Имя выходного файла соответствует вашим ожиданиям (независимо от того, что есть).

И так далее. Как только вы перейдете на этот второй этап, вы начнете определять поведение, которое вы хотите заглушить и издеваться. Например, проверяя, существует ли файл или нет -.NET не упрощает его заглушку, поэтому вам, вероятно, потребуется создать интерфейс и класс адаптера, которые позволят вам изолировать вашу программу от фактической файловой системы (до не говоря уже о фактических файлах CSV и шаблонах слияния почты). Существуют и другие методы, но этот метод довольно стандартный:

public interface IFileFinder { bool FileExists(string path); }

// Concrete implementation to use in production
public class FileFinder: IFileFinder {
    public bool FileExists(string path) { return File.Exists(path); }
}

public class Merger {
    IFileFinder finder;
    public Merger(IFileFinder finder) { this.finder = finder; }
}

В тестах вы пройдете реализацию заглушки:

[Test]
[ExpectedException(typeof(FileNotFoundException))]
public void Fails_When_Csv_File_Does_Not_Exist() {

    IFileFinder finder = mockery.NewMock<IFileFinder>();
    Merger      merger = new Merger(finder);
    Stub.On(finder).Method("FileExists").Will(Return.Value(false));

    merger.Merge("csvPath", "templatePath", "outputPath");
}

Ответ 2

Простые общие рекомендации:

  • Сначала вы пишете единичные тесты. В начале все они терпят неудачу.
  • Затем вы переходите к тестируемому классу и писать код до тех пор, пока испытания, связанные с каждый метод проходит.
  • Сделайте это для каждого общедоступного метода ваши типы.

При написании тестов на устройства вы фактически указываете требования, но в другой форме, легко читаемый код.

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

Чтобы узнать больше об модульном тестировании, я рекомендую очень хорошую книгу: Art of Unit Testing

Вот несколько ссылок на статьи о StackOverflow относительно TDD для более подробной информации и примеров:

Ответ 3

Чтобы иметь возможность unit test вам нужно отделить класс от любых зависимостей, чтобы вы могли просто просто проверить сам класс.

Для этого вам нужно ввести любые зависимости в класс. Обычно вы это делаете, передавая объект, реализующий интерфейс зависимостей, в свой класс в конструкторе.

Mocking frameworks используются для создания макетного экземпляра вашей зависимости, который ваш класс может вызывать во время теста. Вы определяете, что макет ведет себя так же, как и ваша зависимость, и затем проверяйте его состояние в конце теста.

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

http://ayende.com/projects/rhino-mocks.aspx