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

Как вы издеваетесь над файловой системой в С# для модульного тестирования?

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

4b9b3361

Ответ 1

Изменение: установить пакет NuGet System.IO.Abstractions.

Этот пакет не существовал, когда этот ответ был первоначально принят. Оригинальный ответ предоставлен для исторического контекста ниже:

Вы можете сделать это, создав интерфейс:

interface IFileSystem {
    bool FileExists(string fileName);
    DateTime GetCreationDate(string fileName);
}

и создание "реальной" реализации, которая использует System.IO.File.Exists() и т.д. Затем можно смоделировать этот интерфейс, используя насмешливый каркас; Я рекомендую Moq.

Изменение: кто-то сделал это и любезно разместил его в Интернете здесь.

Я использовал этот подход для макетирования DateTime.UtcNow в IClock интерфейс (действительно очень полезно для нашего тестирования, чтобы иметь возможность контролировать поток времени!) и, более традиционно, ISqlDataAccess интерфейс.

Другой подход может заключаться в использовании TypeMock, это позволяет вам перехватывать звонки в классы и заглушать их. Это, однако, стоит деньги, и должны быть установлены на ПК всей вашей команды и Ваш сервер сборки для того, чтобы работать, также, по-видимому, он не будет работать для System.IO.File, так как он не может заглушить mscorlib.

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

Ответ 2

Install-Package System.IO.Abstractions

Эта мнимая библиотека существует сейчас, есть пакет NuGet для System.IO.Abstractions, который абстрагирует пространство имен System.IO.

Существует также набор тестовых помощников System.IO.Abstractions.TestingHelpers, которые - на момент написания - только частично реализованы, но являются очень хорошей отправной точкой.

Ответ 3

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

Пример:

interface IFileWrapper { bool Exists(String filePath); }

class FileWrapper: IFileWrapper
{
    bool Exists(String filePath) { return File.Exists(filePath); }        
}

class FileWrapperStub: IFileWrapper
{
    bool Exists(String filePath) 
    { return (filePath == @"C:\myfilerocks.txt"); }
}

Ответ 4

Я рекомендую использовать http://systemwrapper.codeplex.com/ так как он предоставляет оболочки для наиболее часто используемых типов в пространстве имен System

Ответ 5

Я нашел следующие решения:

  • Записывать тесты интеграции, а не модульные тесты. Для этого вам нужен простой способ создания папки, в которой вы можете сбрасывать материал, не беспокоясь о вмешательстве других тестов. У меня есть простой класс TestFolder, который может создать уникальную папку для каждого тестового метода.
  • Напишите шаблон. System.IO.File. Это создает IFile.cs. Я считаю, что использование этого часто заканчивается тестами, которые просто доказывают, что вы можете писать насмешливые утверждения, но используйте их, когда использование ввода-вывода невелико.
  • Изучите слой абстракции и извлеките файл IO из класса. Создайте для этого интерфейс. Остальные используют интеграционные тесты (но это будет очень мало). Это отличается от предыдущего тем, что вместо того, чтобы делать файл. Читайте, что вы пишете намерение, скажем, ioThingie.loadSettings()
  • System.IO.Abstractions. Я еще не использовал это, но это тот, с которым мне больше всего нравится играть.

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

Ответ 6

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

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

Ответ 7

Трудно было бы издеваться над файловой системой в тесте, поскольку API-интерфейсы .NET не основаны на интерфейсах или расширяемых классах, которые можно было бы издеваться.

Однако, если у вас есть собственный функциональный уровень для доступа к файловой системе, вы можете высмеять это в unit test.

Как альтернатива насмешкам, подумайте о том, чтобы просто создать папки и файлы, которые вам нужны, как часть вашей тестовой установки, и удалить их в методе teardown.

Ответ 8

Чтобы ответить на ваш конкретный вопрос: Нет, нет библиотек, которые позволят вам высмеять вызовы ввода-вывода файлов (что я знаю). Это означает, что для "правильной" модульной проверки ваших типов потребуется, чтобы вы учитывали это ограничение при определении своих типов.

Быстрая заметка о том, как я определяю "правильный" unit test. Я считаю, что модульные тесты должны подтвердить, что вы получаете ожидаемый результат (будь то исключение, вызов метода и т.д.) При условии известных входов. Это позволяет вам настроить условия unit test как набор входов и/или состояний ввода. Лучшим способом, который я нашел для этого, является использование служб на основе интерфейсов и инъекции зависимостей, чтобы каждая ответственность, внешняя по отношению к типу, предоставлялась через интерфейс, переданный через конструктор или свойство.

Итак, имея в виду это, вернитесь к своему вопросу. Я высмеивал вызовы файловой системы, создавая интерфейс IFileSystemService, а также реализацию FileSystemService, которая просто является фасадным методом файловой системы mscorlib. Мой код затем использует IFileSystemService, а не типы mscorlib. Это позволяет мне подключить мой стандартный FileSystemService, когда приложение запущено или издевается над IFileSystemService в моих модульных тестах. Код приложения такой же, независимо от того, как он выполняется, но базовая инфраструктура позволяет легко тестировать код.

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

Ответ 9

Создание интерфейса и издевательство над ним для тестирования - самый простой способ. Однако, как альтернатива, вы можете взглянуть на Microsoft Moles.

Ответ 10

Вы можете сделать это, используя Microsoft Fakes без необходимости изменять свою кодовую базу, например, потому что она уже была заморожена.

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

using Microsoft.QualityTools.Testing.Fakes;
...
using (ShimsContext.Create())
{
     System.IO.Fakes.ShimFile.ExistsString = (p) => true;
     System.IO.Fakes.ShimFile.ReadAllTextString = (p) => "your file content";

      //Your methods to test
}

Ответ 11

Используя System.IO.Abstractions и System.IO.Abstractions.TestingHelpers, например:

public class ManageFile {
   private readonly IFileSystem _fileSystem;
   public ManageFile(IFileSystem fileSystem){

      _fileSystem = fileSystem;
   }

   public bool FileExists(string filePath){}
       if(_fileSystem.File.Exists(filePath){
          return true;
       }
       return false;
   }
}

В своем тестовом классе вы используете MockFileSystem() для имитации файла и создаете экземпляр ManageFile, например:

var mockFileSysteme = new MockFileSystem();
var mockFileData = new MockFileData("File content");
mockFileSysteme.AddFile(mockFilePath, mockFileData );
var manageFile = new ManageFile(mockFileSysteme);

Ответ 12

Общее решение использует некоторый абстрактный API файловой системы (например, Apache Commons VFS для Java): вся прикладная логика использует API и unit test способна для подделки реальной файловой системы с реализацией заглушки (эмуляция в памяти или что-то в этом роде).

В С# аналогичный API существует: NI.Vfs, который очень похож на Apache VFS V1. Он содержит стандартные реализации как для локальной файловой системы, так и для файловой системы в памяти (последний из них можно использовать в модульных тестах из окна).

Ответ 13

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

Ответ 14

Я бы пошел с ответом Джейми Ида. Не пытайтесь издеваться над вещами, которые вы не писали. Там будут всевозможные зависимости, о которых вы не знали - опечатанные классы, не виртуальные методы и т.д.

Другой подход заключается в том, чтобы обернуть методы appopiate с помощью чего-то, что является макетным. например создайте класс под названием FileWrapper, который позволяет получить доступ к методам Файла, но это то, что вы можете высмеять.