Модульное тестирование со сложной структурой каталогов

Я пытаюсь использовать разработку через тестирование для приложения, которое должно считывать много данных с диска. Проблема в том, что данные организованы в файловой системе в несколько сложной структуре каталогов (не по моей вине). Методы, которые я тестирую, должны будут видеть, что большое количество файлов существует в нескольких разных каталогах, чтобы методы могли завершиться.

Решение, которого я пытаюсь избежать, — это просто иметь известную папку на жестком диске со всеми данными в ней. Этот подход отстой по нескольким причинам, одна из которых заключается в том, что если бы мы хотели запустить модульные тесты на другом компьютере, нам пришлось бы копировать на него большой объем данных.

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

Я понимаю, как выполнить модульное тестирование файловых операций ввода-вывода, но как выполнить модульное тестирование такого сценария?

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


person Phil    schedule 19.02.2010    source источник
comment
Я не уверен, что полностью понимаю вашу проблему. Вам нужно только проверить, что определенные файлы существуют в определенных местах, или вам также нужно их прочитать?   -  person Péter Török    schedule 19.02.2010


Ответы (4)


Это имеет перспективу Python. Возможно, вы не работаете на Python, но ответ более или менее применим к большинству языков.

При модульном тестировании с любым внешним ресурсом (например, модулем os) вы должны имитировать внешний ресурс.

Вопрос "как издеваться над os.walk?" (или os.listdir или что вы используете.)

  1. Напишите макетную версию функции. os.walk например. Каждая фиктивная версия возвращает список каталогов и файлов, чтобы вы могли проверить свое приложение.

    Как это построить?

    Напишите «сборщик данных», который выполняет os.walk работу с реальными данными и создает старый плоский список ответов, которые вы можете использовать для тестирования.

  2. Создайте фиктивную структуру каталогов. «было бы сложно написать код для репликации существующей структуры каталогов» обычно не соответствует действительности. Смоделированная структура каталогов — это просто плоский список имен. Боли нет вообще.

Учти это

def setUp( self ):
    structure= [ 
        "/path/to/file/file.x", 
        "/path/to/another/file/file.y", 
        "/some/other/path/file.z",...
    ]
    for p in structure:
        path, file = os.path.split( p )
        try:
            os.makedirs( path )
        except OSError:
            pass
        with open( p, "w" ) as f:
            f.write( "Dummy Data" )

Это все, что требуется для setUp. tearDown похоже.

person S.Lott    schedule 19.02.2010
comment
Я полагаю, что фиктивное создание структуры данных будет иметь ту же проблему, которую родитель поставил перед фактическим созданием структуры данных: код для создания фиктивной структуры данных будет сложным. - person Vivian River; 19.02.2010
comment
@Rising Star: Не обязательно. Вы не издеваетесь над файловой системой, просто достаточно, чтобы приложение думало, что оно работает. - person S.Lott; 19.02.2010
comment
В итоге я написал небольшую одноразовую программу, которая создавала список всех файлов в структуре каталогов (с их полными путями к файлам), сохраняла этот список в текстовый файл и использовала этот текстовый файл для заполнения объекта IFilesystem в моем тестовый класс. На самом деле у объекта нет сложных структур каталогов; он просто просматривает список файлов при каждом вызове FileExists(). - person Phil; 20.02.2010
comment
@Phil: Это прекрасная макетная структура. Что еще вы могли бы хотеть для целей модульного тестирования? - person S.Lott; 20.02.2010
comment
@Phil: виртуальная файловая система? Что это обозначает? В вопросе вы утверждаете, что ваша проблема заключается в обходе структуры каталогов. Вы зафиксировали структуру для своих тестов. Что еще вы хотите для своих тестов? Обновите вопрос, указав конкретные требования, которые вы хотите. Вам не нужна целая файловая система, потому что для ваших тестов требуется только информация о каталоге, которую вы уже захватили. Если вы хотите больше, обновите вопрос, указав конкретные требования. - person S.Lott; 20.02.2010
comment
я шучу. Мне не нужна виртуальная файловая система. Просто было бы опрятно. - person Phil; 20.02.2010
comment
@Phil: Почему вся эта сложность подходит для модульного теста? Звучит как сокрушительное количество бесполезных фитуритов. Если бы вы могли перечислить специфические особенности виртуальной файловой системы, которую вы фактически собираетесь использовать для модульных тестов, я думаю, вы бы увидели, что уже все построили. Я не думаю, что есть что-то большее, чем то, что вы уже сделали. - person S.Lott; 21.02.2010
comment
Причина, по которой я говорю, что это будет аккуратно, заключается в том, что я хочу уменьшить объем кода, который мне нужно написать. Написанный мной фиктивный класс файловой системы не слишком сложен, но достаточно сложен, чтобы нуждаться в собственных модульных тестах. Это не обязательно плохо, но если бы кто-то уже создал библиотеку для имитации файловой системы, я бы просто использовал ее, и жизнь была бы проще. И это не говоря уже о том, что мне теперь предстоит создать класс-производитель, который также реализует IFilesystem, который был бы просто классом-оболочкой для уже существующих библиотек. Опять же, это не ужасно, но я хотел бы избежать этого, если смогу. - person Phil; 22.02.2010
comment
@Phil: Вы написали фиктивную файловую систему, для которой требовались модульные тесты? И все, что ему нужно сделать, это ответить списком файлов, которые вы уже собрали с производства? Я что-то не получаю. Похоже, вы написали фиктивную файловую систему, которая делает слишком много. - person S.Lott; 22.02.2010
comment
В моем интерфейсе есть только те методы, которые мне нужны, и это довольно простые методы, такие как GetDirectories() и GetFiles(). Я думаю, что моя проблема заключалась в том, что моя фиктивная файловая система должна была анализировать список путей к файлам, чтобы выяснить, какие каталоги существуют, и, подумав об этом, этой дополнительной сложности можно было легко избежать. Таким образом, фиктивный класс не делает слишком много, но то, что он делает, можно упростить. Думаю, я понимаю, о чем вы говорите. Спасибо, что нашли время, чтобы помочь мне обдумать это. - person Phil; 22.02.2010
comment
@Phil: фиктивный класс не слишком много делает. Это то, к чему мы стремимся. Вот почему меня заинтересовал этот вопрос. И почему я продолжаю спрашивать, что еще он должен сделать. Если ответ не более того, то вы уже описали все требования и, похоже, можете их удовлетворить. - person S.Lott; 22.02.2010

Я бы определил набор интерфейсов, которые имитируют файловую систему, например IDirectory и IFile, а затем использовал Test Doubles для создания представления структуры каталогов в памяти.

Это позволит вам проводить модульное тестирование (и изменять) эту структуру в соответствии с вашими пожеланиями.

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

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

person Mark Seemann    schedule 19.02.2010
comment
Это все еще непростая задача, но я думаю, что я пойду по этому пути. Попытка имитировать файловую систему помогает мне более эффективно отделить доступ к данным от бизнес-логики, что является лучшим дизайном. - person Phil; 19.02.2010

Вау, это звучит как зверь. Я сам занимался тестированием.

Похоже, что основное внимание в вашем вопросе уделяется «Как мне настроить большое количество файлов, чтобы я мог тестировать методы, проверяющие существование указанных файлов?»

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

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

Рой Ошеров говорит в The Art of Unit Testing, что это отличная идея — поддерживать и версионировать тестовый код по мере того, как поддерживается и версионируется ваш проект.

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

Мое решение: поместить фиктивные данные в систему управления версиями.

person Vivian River    schedule 19.02.2010

Возможным решением было бы создание фиктивной структуры файлов и каталогов из файла tar, который развертывает ваш метод установки.

person mouviciel    schedule 19.02.2010