поддельные каталоги для модульного тестирования .net

Я пытаюсь создать модульный тест для кода, подобного этому:

foreach (string domainName in Directory.GetDirectories(server.Path))
{
     HandleDomainDirectory(session, server, domainName);
}

Проблема в том, что я использую класс System.IO.Directory в своем коде. Как я могу создать метод тестирования, который не будет зависеть от какой-либо папки на моем жестком диске. Другими словами, как я могу подделать ответ «Directory.GetDirectories(server.Path)»? (Обратите внимание, я контролирую объект «сервер» в своем классе, поэтому я могу указать любой путь, который захочу)

Спасибо.


person Dig    schedule 18.04.2011    source источник


Ответы (4)


Вместо того, чтобы вызывать Directory.GetDirectories(server.Path) напрямую, вы можете создать интерфейс, подобный IDirectoryResolver, с одним методом, который принимает строку пути и возвращает список каталогов. Классу, содержащему приведенный выше код, потребуется свойство или поле типа IDirectoryResolver, которое можно внедрить через конструктор или сеттер.

Для вашего производственного кода вы должны создать новый класс, который реализует интерфейс IDirectoryResolver. Этот класс может использовать метод Directory.GetDirectories в своей реализации метода интерфейса.

Для модульного тестирования вы можете создать класс MockDirectoryResolver, реализующий IDirectoryResolver (или использовать фиктивную библиотеку для создания фиктивного экземпляра интерфейса). Макетная реализация может делать все, что вам нужно.

person Andy White    schedule 18.04.2011
comment
На мой взгляд, самый простой ответ и решение, которое вы можете использовать для гораздо большего количества вариантов использования. - person JKL; 10.04.2018

Вы бы ввели класс-оболочку.

public class DirectoryFetcher
{
     public virtual List<string> GetDirectoriesIn(string directory)
     {
          return Directory.GetDirectories(directory);
     }
}

А затем введите это:

foreach(string directory in _directoryFetcher.GetDirectoriesIn(server.Path))
{
    // Whatever
}

Затем вы можете издеваться над этим парнем в точке внедрения (в этом примере используется Moq и внедрение конструктора):

Mock<DirectoryFetcher> mockFetcher = new Mock<DirectoryFetcher>();

mockFetcher.Setup(x => x.GetDirectoriesIn("SomeDirectory")).Returns(new List<string>
{
    "SampleDirectory1",
    "SampleDirectory2"
});

MyObjectToTest testObj = new MyObjectToTest(mockFetcher.Object);

// Do Test
person Tejs    schedule 18.04.2011

При общении с внешним миром, таким как файловая система, базы данных, веб-службы и т. д., вы всегда должны рассматривать возможность использования классов-оболочек, подобных тем, которые предлагались ранее. Тестируемость — один из основных аргументов, но еще более весомый: внешний мир меняется, и вы не можете его контролировать. Папки перемещаются, права пользователей меняются, появляются новые диски и удаляются старые. Вы хотите заботиться о таких вещах только в одном месте. Следовательно, оболочка -- давайте назовем ее DirectoryResolver, как предлагал ранее Энди Уайт.

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

person Morten    schedule 19.04.2011

Лучшим решением, которое я нашел, было использование Moles. Код очень специфический и должен делать очень специфические вещи. Обертывание его классом-оболочкой будет избыточным. Единственная причина, по которой мне нужен класс-оболочка, - это писать тесты. Moles позволяет мне писать тесты без какого-либо класса-обертки :)

person Dig    schedule 21.04.2011