C # (модульное тестирование): мне нужно сделать невозможным запись в файл с помощью кода - PullRequest
0 голосов
/ 12 января 2011

В основном, вот ситуация.У меня есть следующее:

public IService Service { get; set; } //Set to MyMockedService class.

public Boolean DoFoo()
{
    //possible other ways of returning true/false...

    Boolean success = true;

    //Get FileInfo[] items

    foreach (var item in items)
        DoOtherFoo(item);
}

public Boolean DoOtherFoo(FileInfo fileInfo)
{
    String filepath = //manipulate fileInfo.FullName;

    Byte[] file = Service.GetFile(filepath)
    try
    {
        WriteBinaryFile(filepath, file); //How can I force file writing to throw an exception
    }
    catch (Exception)
    {
        return false;
    }
}

В принципе, при тестировании DoFoo () у меня есть много путей, которые могут возвращать true / false.Я протестировал все из них, кроме последнего ... где он пытается записать файлы, и если хотя бы один из файлов не может быть записан по какой-либо причине, он завершается неудачно и возвращает false.Сначала я подумал, что если я попытаюсь установить неверное имя файла, такое как «bad * file», это вызовет исключение в WriteFile, но я даже не зашел так далеко, потому что не могу создать объект FileInfo, используя недопустимые символы.Поэтому я ищу другой способ сделать так, чтобы было невозможно написать файл, чтобы я мог получить ложное возвращение.

Ответы [ 5 ]

4 голосов
/ 12 января 2011

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

public interface IStorage
{
  bool StoreToFile(string path, string file, byte[] data);
}

public class Storage : IStorage
{
  public bool StoreToFile( ... )
  {
     return WriteToFile( ... );
  }
}

public class StorageMock : IStorage
{
   public bool StoreToFile (...)
   {
      return false;  //or true, depends on you test case
   }
}

Теперь в тестах вы можете "заменить" реальное значение фальшивым. Это называется издевательством.

Проект, который принимает во внимание, называется «Инверсия контроля». Существует также множество платформ, которые позволяют использовать «Investion of Control» посредством внедрения зависимостей (StructureMap, Ninject, Wisdor)

3 голосов
/ 12 января 2011

Является ли WriteBinaryFile метод в том же class?

Вы можете создать объект с этой исключительной ответственностью, но начните с абстракции:

public interface IBinaryFileWriter
{
    void WriteBinaryFile(string filepath, Byte[] file);
}

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

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

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

1 голос
/ 12 января 2011

Ваш модульный тест может использовать System.IO.File.Open (...) с FileShare, установленным на None.Любой другой процесс не сможет открыть этот файл.

0 голосов
/ 12 января 2011

Вот декомпилированный код для ctor FileInfo

public FileInfo(string fileName)
{
    if (fileName == null)
    {
        throw new ArgumentNullException("fileName");
    }
    base.OriginalPath = fileName;
    string fullPathInternal = Path.GetFullPathInternal(fileName);
    new FileIOPermission(FileIOPermissionAccess.Read, new string[] { fullPathInternal }, false, false).Demand();
    this._name = Path.GetFileName(fileName);
    base.FullPath = fullPathInternal;
}

Таким образом, после создания FileInfo вы можете установить для FullPath и OriginalPath недопустимый путь к файлу путем отражения и сделать исключение для метода WriteBinary

Просто так:

 FileInfo info = new FileInfo("c:\\1.txt");
 info.GetType().BaseType.GetField(
      "FullPath", 
      BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance)
   .SetValue(info, "invalidpath");
 info.GetType().BaseType.GetField(
      "OriginalPath", 
       BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance)
   .SetValue(info, "invalidpath");
0 голосов
/ 12 января 2011

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

...