Как Вы дразните файловую систему в C# для поблочного тестирования?

Это лучшее решение, которое я нашел с помощью клиента Python

  # Initialize the scroll
  page = es.search(
  index = 'yourIndex',
  doc_type = 'yourType',
  scroll = '2m',
  search_type = 'scan',
  size = 1000,
  body = {
    # Your query's body
    })
  sid = page['_scroll_id']
  scroll_size = page['hits']['total']

  # Start scrolling
  while (scroll_size > 0):
    print "Scrolling..."
    page = es.scroll(scroll_id = sid, scroll = '2m')
    # Update the scroll ID
    sid = page['_scroll_id']
    # Get the number of results that we returned in the last scroll
    scroll_size = len(page['hits']['hits'])
    print "scroll size: " + str(scroll_size)
    # Do something with the obtained page

https://gist.github.com/drorata/146ce50807d16fd4a6aa

Использование Java-клиента

import static org.elasticsearch.index.query.QueryBuilders.*;

QueryBuilder qb = termQuery("multi", "test");

SearchResponse scrollResp = client.prepareSearch(test)
        .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC)
        .setScroll(new TimeValue(60000))
        .setQuery(qb)
        .setSize(100).execute().actionGet(); //100 hits per shard will be returned for each scroll
//Scroll until no hits are returned
do {
    for (SearchHit hit : scrollResp.getHits().getHits()) {
        //Handle the hit...
    }

    scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(60000)).execute().actionGet();
} while(scrollResp.getHits().getHits().length != 0); // Zero hits mark the end of the scroll and the while loop.

https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-search-scrolling.html

139
задан pupeno 6 July 2009 в 14:42
поделиться

9 ответов

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

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

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

 interface IFileSystem {
 bool FileExists (строка имя_файла);
 DateTime GetCreationDate (строка fileName);
}

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

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

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

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

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

143
ответ дан 23 November 2019 в 23:21
поделиться

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

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

1
ответ дан 23 November 2019 в 23:21
поделиться

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

Однако,

1
ответ дан 23 November 2019 в 23:21
поделиться

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

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

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

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

1
ответ дан 23 November 2019 в 23:21
поделиться

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

Пример:

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"); }
}
10
ответ дан 23 November 2019 в 23:21
поделиться

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

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

-2
ответ дан 23 November 2019 в 23:21
поделиться

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

-1
ответ дан 23 November 2019 в 23:21
поделиться

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

1
ответ дан 23 November 2019 в 23:21
поделиться

Я нашел следующие решения этой проблемы:

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

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

3
ответ дан 23 November 2019 в 23:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: