Обучение TDD на простом примере - PullRequest
23 голосов
/ 09 декабря 2010

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

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

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

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

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

Я думаю, что некоторые общие рекомендации по TDD были бы очень полезны!

Ответы [ 3 ]

34 голосов
/ 09 декабря 2010

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

  • Пользователь указывает нулевое местоположение файла 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");
}
6 голосов
/ 09 декабря 2010

Простое общее руководство:

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

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

Глядя на это с другой стороны: когда вы получаете новый класс в штучной упаковке и юнит-тесты для него, вы должны прочитать юнит-тесты, чтобы увидеть, что делает класс и как он ведет себя.

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

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

2 голосов
/ 09 декабря 2010

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...