Модульное тестирование класса, использующего файловую систему - PullRequest
6 голосов
/ 11 февраля 2010

У меня есть класс, который выводит простой файл отчета. Он считывает некоторые идентификационные номера записей из файла XML: каждый из них используется для поиска соответствующей записи, хранящейся в базе данных. Затем он записывает детали каждой записи в файл CSV.

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

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

Мой проект использует NHibernate для доступа к данным, Spring .NET для внедрения зависимостей и Rhino.Mocks для модульного тестирования.

В настоящее время у меня есть что-то похожее на это:

public class ReportBiz
{
    //Access to repository, populated by Spring
    internal ICardRequestDAO CardRequestData { get;set;} 

    //This normally returns a FileStream containing data from the XML file. When testing this is overridden by using a Rhino.Mocks partial mock and returns a MemoryStream
    internal virtual Stream GetSourceStream()
    {
        //Load file and return a Stream
        ...
    }

    //This normally returns a FileStream where CSV data is saved. When testing this is overridden by using a Rhino.Mocks partial mock and returns a MemoryStream
    internal virtual Stream GetOutputStream()
    {
        //Create file where CSV data gets saved and return a Stream
        ...
    }

    public void CreateReportFile()
    {
        Stream sourceStream = GetSourceStream();
        ...

        //Create an XmlDocument instance using the stream
        //For each XML element, get the corresponding record from the database
        //Add record data to CSV stream     
        ...
    }
    }

Было бы лучше использовать какую-то собственную фабрику или что-то в этом роде и передавать потоки в конструктор? Но что делать, если есть какая-то бизнес-логика, например, имя файла определяется на основе результатов запроса?

Или все-таки проблема с доступом к файлу не является проблемой?

Извиняюсь, если я упускаю что-то очевидное. Буду благодарен за любой совет.

Ответы [ 2 ]

8 голосов
/ 11 февраля 2010

Самый простой способ сделать доступ к файлу симулятивным при сохранении контроля над жизненным циклом одноразовых ресурсов - это ввести StreamFactory в ваш класс:

public class ReportBiz {

    private IStreamFactory streamFactory;

    public ReportBiz(IStreamFactory streamFactory) {
        this.streamFactory = streamFactory
    }

    public void CreateReportFile() {
        using(Stream stream = this.streamFactory.CreateStream()) {
            // perform the important work!
        }
    }
}

Когда задействовано больше бизнес-логики, ваш фабричный метод может быть немного более сложным, но ненамного:

public void CreateReportFile() {
    string sourcePath   = this.otherComponent.GetReportPath();
    using(Stream stream = this.streamFactory.CreateStream(sourcePath)) {
        // perform the important work!
    }
}
2 голосов
/ 11 февраля 2010

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

Ключевым моментом в этом сценарии является то, что вы должны признать, что у вас есть три этапа в потоке данных:

  • Чтение данных : анализ данных является уникальной, особой проблемой
  • Содержимое вывода : вы должны убедиться, что при заданных правильных данных у вас есть правильный вывод строки CSV
  • Запись этого содержимого в файл

Честно говоря, проблема записи всего файла не является большой проблемой - .NET Framework предоставляет довольно хорошо протестированные функции записи файлов, и это выходит за рамки вашего тестирования. Большинство проблем, с которыми вы столкнетесь, - это точность CSV, которую вы выплевываете на файлы.

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

...