У меня есть класс, который производит простой файл отчета. Это читает некоторые рекордные Идентификационные номера из XML-файла: каждый используемый для нахождения записи соответствия сохранен в базе данных. Это затем выписывает детали каждой записи к файлу CSV.
Я задаюсь вопросом - что лучший способ состоит в том, чтобы организовать его так, чтобы было легко протестировать, уже следует за принципами инкапсуляции? Я заключаю, что это лучше стараться не взаимодействовать с файловой системой, если не абсолютно необходимо, таким образом, я имею дело с Потоковыми объектами. Когда поблочное тестирование, я могу использовать частичные фиктивные объекты для переопределения битов, которые читают или пишут в файлы.
Я также не уверен в том, когда/где расположить потоки, не делая поблочное тестирование хитрым. Похоже, что мне, возможно, придется выставить потоки модульному тесту.
Мой проект использует NHibernate для доступа к данным, Spring.NET для внедрения зависимости и Носорог. Насмешки для поблочного тестирования.
В настоящее время у меня есть что-то подобное этому:
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
...
}
}
Было бы лучше использовать некоторую пользовательскую фабрику или что-то и передать потоки в конструктора? Но что относительно того, если существует некоторая бизнес-логика, включенная, например, имя файла определяется на основе результатов запроса?
Или разве целой вещью доступа к файлу не является проблема, в конце концов?
Извинения, если я пропускаю что-то очевидное. Я был бы благодарен за любой совет.
Самый простой способ сделать доступ к файлам имитируемым, сохранив при этом контроль над жизненным циклом одноразовых ресурсов, - это внедрить 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!
}
}
Вам придется как-то высмеивать свои потоки, чтобы не раскрывать их для тестирования, потому что мясо вашей бизнес-логики заключается в правильном получении входных и выходных строк.
Самое главное в этом сценарии то, что вы должны осознать, что у вас есть три этапа в потоке данных:
Честно говоря, проблема записи в файл не представляет особой проблемы - . NET Framework предоставляет довольно хорошо протестированные функции записи файлов, и это выходит за рамки вашего тестирования. Большинство проблем, с которыми вы столкнетесь, будут связаны с точностью CSV, который вы выплевываете в файлы.
В качестве предостережения, я бы посоветовал не создавать свой собственный CSV writer. Вы должны попытаться найти уже существующие библиотеки CSV -- их много в сети.