Тестова розробка: хороший / прийнятий спосіб тестування операцій з файловою системою?


14

На даний момент я працюю над проектом, який генерує таблицю (серед іншого) на основі вмісту файлової системи, а в свою чергу вносить деякі модифікації метаданих на речі, які вона знаходить. Питання: як слід писати тести навколо цього чи встановлювати? Чи є простий спосіб насмішити це? Або я повинен встановити "пісочницю"?

Відповіді:


13

Як завжди в TDD із зовнішніми ресурсами: ви створюєте один або кілька інтерфейсів для операцій з вашою файловою системою та "знущаєтесь з них". Ви хочете перевірити свій "генератор таблиць" та код модифікації метаданих, а не самі операції з файловою системою (швидше за все, ви використовуєте готові реалізації бібліотеки для доступу до файлової системи).


TDD не рекомендує знущатися над тестуванням блоку, який перевіряється. Дивіться (e, g) solnic.eu/2014/05/22/mocking-and-ruby.html
сорв

1
@soru: Не рекомендується ця відповідь. Він рекомендує спочатку створити інтерфейси, а потім знущатися над інтерфейсом . Таким чином, ви протестуєте логіку бізнесу, але не інтерфейс файлової системи.
sleske

5
Але це звучить так, як бізнес-логіка визначена з точки зору файлів та каталогів. Отже, матеріал, який викликає API файлової системи, - це те, що потребує тестування. Тестування будь-якої пов'язаної нефайлової логіки бізнесу не потребує глузування; просто випробуй це.
soru

@soru право, тому ви створюєте тонкий шар навколо файлів і папок з таким інтерфейсом, який визначає, що всі доменні операції знаходяться на стороні клієнта, а сторона реалізації є тривіальною, щоб бути впевненою, що вона працює без тестування одиниць (інтеграційні тести будуть все одно потрібно). Подібно до ідеї діалогового вікна Humble в коді ui або з використанням макетного сховища в коді, який працює на стійких об'єктах.
Жуль

2
Настільки ефективно ми відмовляємося від тестування фактичного класу, який взаємодіє з файловою системою, базою даних тощо ... замість цього ми створюємо іншу реалізацію з тим же інтерфейсом, що і макет / заглушка, але фактичний клас ми залишаємо без будь-якого тестування одиниць, тому що ми вважаємо, що ми не можемо його перевірити, і ми повинні зробити тестування інтеграції, щоб перевірити його. Це правильно?
Андрій Савіних

11

Що не так у тестовій файловій системі?

Створіть папку шаблонів / структуру каталогів, яка має достатньо вмісту, щоб перевірити вашу діяльність.

Під час налаштування вашого тестового пристрою скопіюйте цю початкову структуру (рекомендую вам скопіювати шаблон і розпакуйте його до тестової області). Запустіть свої тести. Видаліть всю річ під час зриву.

Проблема з глузуванням - це, по-перше, файлові системи, ОС та бази даних, які належать до вашого проекту, насправді не кваліфікуються як зовнішні ресурси, а по-друге, глузування системних дзвінків низького рівня є трудомісткими та схильними до помилок.


5
Знущання з операцій з файловою системою створить набагато швидкіші (!) Тести, ніж виконання реальної файлової системи, і якщо це більше "схильний до помилок", то я б сказав, що це залежить від реалізації. Тим не менш, я вважаю, що ваша пропозиція чудово підходить для створення автоматизованих тестів на інтеграцію (що я зазвичай роблю першим, коли не роблю TDD). Але ОП спеціально попросив TDD, і випробування блоку TDD повинні бути швидкими.
Док Браун

1
Я думаю, що в разі, якщо знущаються над цим файловими системами, в ідеалі має бути цілий API, який записує і підтримує якась група, тому що ви винаходите колесо, якщо ви зробите щось важливе з файловою системою.
Френк Хілеман

2
@Doc Brown - Я начебто припускаю, що він хоче робити dir, видаляти та перейменовувати операції типу, у всіх яких є крайні випадки, з яких було б боляче знущатися. Крім того, на сучасному обладнанні розпакування декількох невеликих файлів у каталог лише трохи повільніше, ніж завантаження класу Java - все-таки IO.
Джеймс Андерсон

Чим більше я думаю про тестову файлову систему, тим більше мені це подобається.
Френк Хілеман

3

Це та річ, яка вам обов'язково потрібна для інтеграційного тесту, оскільки файлові системи реального світу мають дивне поведінку (як, наприклад, Windows не дозволить видалити файл, якщо будь-який процес, включаючи делетер, відкритий).

Таким чином, підхід TDD полягає в тому, щоб спершу написати тест на інтеграцію (TDD, строго кажучи, не має чітких понять "тест на одиницю" та "тест на інтеграцію"; це лише тести). Цілком ймовірно, що цього буде достатньо; так що робота виконана, зупиніться, йдіть додому .

Якщо ні, то з’явиться деяка внутрішня складність, яку не просто адекватно перевірити, організувавши файли. У такому випадку ви просто виймаєте цю складність, кладете її в клас і пишете одиничні тести для цього класу . Цілком ймовірно, що ви знайдете, що цей загальний клас також може бути використаний у випадках баз даних, файлів xml тощо.

Ні в якому разі ви не брали б основоположне ядро ​​коду, який ви пишете, і «знущаєтесь над ним», щоб написати тести, які пройдуть те, чи не відповідає тестованому пристрою чи ні.


Ця відповідь справді поставила це в перспективу для мене - 'unit test' and 'integration test'; they are just tests.я думаю, що реально це буде найкращим рішенням для мого випадку - мені дійсно потрібно перевірити бібліотеки файлової системи, які я використовую для кращих випадків, і як програма повинна реагувати на ті. Якщо я перейду до іншої бібліотеки файлової системи, мені не потрібно буде переписувати купу макетів / тестових кодів для роботи з новою бібліотекою, але наявність структури тестової папки та тестів інтеграції зробить це набагато простіше.
tehDorf

2

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

Для того, щоб докласти зусиль, щоб 'інтерфейси до вашої операції з файловою системою і' знущатися над ними '', як відповідь @Doc Браун пропонується якомога меншою, корисно використовувати двійкові потоки Java чи зчитування тексту (або еквівалент в c # або мову програмування, яку ви використовуєте), а не використовувати файли з іменами безпосередньо у вашому класі, розробленому tdd.

Приклад:

Використовуючи Java, я реалізував клас CsvReader

public class CsvReader {
    private Reader reader;

    public CsvReader(Reader reader) {
        this.reader = reader;
    }
}

Для тестування я використовував такі дані пам'яті

String contentOfCsv = "TestColumn1;TestColumn2\n"+
    "value1;value2\n";

CsvReader sut = new CsvReader(java.io.StringReader(contentOfCsv));

або поглинати тестові дані в ресурси

CsvReader sut = new CsvReader(getClass().getResourceAsStream("/data.csv"));

У виробництві я використовую файлову систему

CsvReader sut = new CsvReader(new BufferedReader( new FileReader( "/import/Prices.csv" ) ));

Таким чином мій CsvReader не залежить від файлової системи, а від абстракції "Reader", де є реалізація для файлової системи.


2
Єдина проблема тут полягає в тому, що в ОП говорили не про файлові операції, а про операції з файловою системою та операції з метаданними - я думаю, він мав на увазі щось на зразок перерахування всіх файлів у каталозі, оновлення деякої інформації EXIF ​​у всіх файлах зображень тощо.
Док Браун

Це вірно.
Kirbinator

1
Ви можете створити IDirectoryLister, який має метод String [] Список (каталог рядків); тоді FakeDirectoryLister може реалізувати цей метод, просто повернувши новий String [] {".", "..", "foo.bat", "bar.exe"};
Андерс Лінден

0

Створіть обгортку для операцій з файловою системою. У тестах пройдіть макет, який реалізує той же інтерфейс, що і обгортка. На виробництві передайте в обгортку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.