Знущання над базою даних у node.js?


79

Як би я знущався з бази даних у моїй програмі node.js, яка в даному випадку використовує mongodbяк серверну частину для REST API блогу?

Звичайно, я міг би встановити для бази даних конкретну testingбазу даних, але я все одно зберігав би дані і не тестував лише свій код, а й базу даних, тому я фактично роблю не модульне тестування, а інтеграційне тестування.
То що треба робити? Створити обгортки баз даних як середній шар між програмою та db та замінити DAL під час тестування?

// app.js  
var express = require('express');
    app = express(),
    mongo = require('mongoskin'),
    db = mongo.db('localhost:27017/test?auto_reconnect');

app.get('/posts/:slug', function(req, res){
    db.collection('posts').findOne({slug: req.params.slug}, function (err, post) {
        res.send(JSON.stringify(post), 200);
    });
});

app.listen(3000);

// test.js
r = require('requestah')(3000);
describe("Does some testing", function() {

  it("Fetches a blogpost by slug", function(done) {
    r.get("/posts/aslug", function(res) {
      expect(res.statusCode).to.equal(200);
      expect(JSON.parse(res.body)["title"]).to.not.equal(null);
      return done();
    });

  });
));

Відповіді:


128

Я не думаю, що пов'язаний з базою даних код можна перевірити належним чином, не протестувавши його за допомогою програмного забезпечення бази даних. Це тому, що код, який ви тестуєте, - це не просто javascript, а й рядок запиту до бази даних. Незважаючи на те, що у вашому випадку запити виглядають простими, ви не можете покладатися на те, що це буде назавжди.

Тож будь-який рівень емуляції бази даних обов'язково реалізує всю базу даних (за винятком можливостей дискового сховища). До того часу ви закінчуєте тестування інтеграції з емулятором бази даних, хоча ви називаєте це модульним тестуванням. Іншим недоліком є ​​те, що в результаті емулятор бази даних може мати інший набір помилок порівняно з базою даних, і вам може знадобитися кодувати як емулятор бази даних, так і базу даних (подібно до ситуації з IE проти Firefox проти Chrome тощо). ).

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


1
Ви знаєте, ви робите добру думку. Незважаючи на те, що модульне тестування має феноменальну мету (тобто ізоляцію), ви зробили сильну думку щодо інтеграційного тестування.
Mike Perrenoud

4
@MichaelPerrenoud: Мені подобається правило, викладене у відповіді christkv: "Не знущайтесь над тим, що вам не належить " . Хоча це не вдається в подробиці, чому це погана ідея, це легко запам’ятати правило.
slebetman

1
Я не погоджуюся з цією відповіддю, в meteorjs вони якось налаштовують тестову БД під час запуску тестів (я припускаю, що це не фальшива бібліотека, а тимчасовий файл), і це дуже зручно. Було б дуже корисно мати об’єкт, який поводиться точно так само, як монгодб і очищає після себе. Незалежно від того, чи все це в пам'яті, чи тимчасовий файл - це деталь реалізації, тому вам не потрібно дублювати код. Я згоден з тим, що люди, які роблять водія, повинні бути тими, хто робить макет об'єкта.
Урі

Думаю, я також не згоден з цією відповіддю. Питання OP було спрощеним, оскільки це лише контролер та база даних. А як щодо всієї логіки додатків, яка робить сервери серверами, а не лише каналами з БД в Інтернет? Уявляючи, що у вас є об’єкт, який ви хочете перевірити, а потім внести в базу даних, чи не справедливо уявляти щось на зразок інтеграційного тесту для перевірки, чи взаємодія все ще працює, і модульних тестів, щоб перевірити всю перевірку? Взявши цю відповідь буквально, як можна перевірити що-небудь із даними, що походять з бази даних? Скільки часу займають ваші збірки ??
user2152081

1
Подивіться, знущання над дзвінками БД є надзвичайно дурним і призводить лише до напруженої роботи. Я думаю, що люди пропускають всю суть тестів. Це показує, що введення відповідає виводу. Для функції, що викликає БД, Ви не можете цього точно знати, якщо цей тест не включає виклик db. Найкращий спосіб зробити це, щоб тестова конфігурація вказувала на екземпляр MongoDB, який працює в пам'яті. Таким чином, вам не доводиться мати справу з дисковим введенням / виведенням, а також ви виконуєте головний момент "глузування", який полягає у запуску з пам'яті.
Glstunna

42

Існує загальне емпіричне правило, коли йдеться про глузування, яке є

Не глузуйте з того, що вам не належить.

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

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


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

Як ви працюєте зі сторонніми API? Відеомагнітофон-помічник?
Dogweather

Ви найкращий сер!
Марко Лаццері,

41

Поки що я не згоден із вибраною відповіддю чи іншими відповідями.

Чи не було б чудово, якби ви могли ловити помилки, породжені хаотичними та багаторазово брудними змінами, внесеними до схем БД та вашого коду ДО того, як він потрапить до контролю якості? Б'юсь об заклад, більшість кричала б, так!

Ви, безсумнівно, можете і повинні ізолювати та протестувати ваші схеми БД. І ви не робите це на основі емулятора чи важкого зображення чи відпочинку вашої БД та машини. Ось такі речі, як SQLite, є лише одним із прикладів. Ви знущаєтесь із цього, базуючись на полегшеному екземплярі в пам'яті та зі статичними даними, які не змінюються в тому екземплярі в пам'яті, що означає, що ви справді тестуєте свою БД ізольовано і можете також довіряти своїм тестам. І, очевидно, це швидко, тому що він є в пам’яті, скелетом і оброблений на кінець тестового запуску.

Так що так, вам слід, і ви повинні протестувати схему, яка експортується в дуже легкий екземпляр пам’яті будь-якого движка / середовища виконання, який ви використовуєте, і який разом із додаванням дуже невеликої кількості статичних даних стає вашою ізольованою знущаною БД.

Ви періодично експортуєте свої реальні схеми зі своєї реальної БД (автоматизовано) та імпортуєте / оновлюєте їх у своє світло в екземплярі БД пам’яті перед кожним натисканням на QA, і ви миттєво дізнаєтесь, чи відбулися будь-які останні зміни БД, зроблені адміністраторами БД або іншими розробники, які останнім часом змінювали схему, пройшли будь-які тести.

Хоча я вітаю зусилля, щоб спробувати зробити все можливе, щоб відповісти, я б проголосував за поточну відповідь, якби міг, але я новачок і ще не набув достатньої репутації, щоб забезпечити свою здатність це робити.

Що стосується людини, яка відповіла "не знущайтесь над тим, що вам не належить". Я думаю, він мав намір сказати "не перевіряйте нічого, що вам не належить". Але ви глузуєте з речей, якими не володієте! Тому що саме ті речі, що не перевіряються, потрібно ізолювати!

Я планую поділитися з вами ЯК, і в майбутньому оновлю цю публікацію реальним прикладом коду JS!

Це те, що роблять багато перевірених команд постійно. Ви просто повинні зрозуміти, як.


5
Я хотів би висловитись за, але не можу, якщо це не пом’якшить питання і не запропонує рішення. Будь ласка, оновіть свою публікацію, коли з’явиться можливість.
Шанімаль

5
2018 рік, і досі немає "як", безумовно, було цікаво прочитати більше.
MacK

3
Я голосував проти з 3 років і далі, як і раніше.
Ян,

5

Моїм найкращим підходом до модульного тестування коду БД будь-якою мовою є доступ до Монго через абстракцію сховища (тут є приклад http://iainjmitchell.com/blog/?p=884 ). Реалізація буде відрізнятися з точки зору функціональних можливостей БД, але якщо ви видалите весь код Mongo з вашої власної логіки, ви зможете здійснити модульний тест. Просто замініть реалізацію сховища Mongo на затуплену версію, яка є простою. Наприклад, просто зберігайте об'єкти у простій колекції словників, що зберігається в пам'яті.

Ви отримаєте переваги модульного тестування власного коду таким чином без залежностей БД, але вам все одно доведеться робити тести інтеграції щодо основної БД, тому що ви, мабуть, ніколи не зможете наслідувати ідіосинкрази реальної бази даних, як це робили інші. сказав тут. Різноманітні речі, які я знайшов, такі ж прості, як індексація в безпечному режимі та без безпечного режиму. Зокрема, якщо у вас є унікальний індекс, ваша фіктивна пам’ять може вшановувати це у всіх випадках, але Mongo не обійдеться без безпечного режиму.

Тож, хоча вам все одно доведеться тестувати проти БД для деяких операцій, ви, безумовно, зможете правильно перевірити власну логіку за допомогою загальмованої реалізації сховища.


але в якийсь момент ваш реальний код реалізації повинен посилатися на реальні виклики даних. Я припускаю, що ви вводите Інтерфейс у ваше сховище до реального коду запиту рівня даних?
PositiveGuy

1
Спробуйте використовувати Docker. Я вирішив багаторічні проблеми з конфігурацією баз даних та встановленнями пакетів, використовуючи Docker для запуску контейнерів, що запускають бази даних, ініціалізовані конкретними тестовими даними для сценарію. Насправді я запускаю стеки з 3 контейнерів: один із БД, другий із кодом програми та другий із тестовим драйвером. Якщо ваш набір даних помірний за розміром, ви можете навіть крутити паралельні екземпляри цих стеків, що значно скорочує ваш цикл тестування.
ово

4

Мета знущань - пропустити складність і модульний тест власного коду. Якщо ви хочете написати тести e2e, використовуйте db.

Написання коду для налаштування / виведення тестової БД для модульного тестування є технічним боргом і неймовірно незадовільним.

У npm є фіктивні бібліотеки:

mongo - https://www.npmjs.com/package/mongomock

мангуст - https://www.npmjs.com/package/mockgoose

Якщо вони не підтримують потрібні вам функції, тоді так, можливо, вам доведеться використовувати справжню річ.


1
mongo-mock не підтримує операції агрегування, наприклад, що може бути проблемою, я почав його використовувати, а в кінці закінчив використовувати справжнє програмне забезпечення з базою даних
testOnly

Також при зміні монго-макету на монгодб багато речей зламалося, тому це перемогло мету
zardilior

3

У мене була ця дилема, і я вирішив працювати з тестовою БД і очищати її кожного разу, коли починається тест. (як скинути все: https://stackoverflow.com/a/25639377/378594 )

За допомогою NPM ви навіть можете створити тестовий скрипт, який створює файл db і очищає його після.


це насправді хороший підхід, і я б рекомендував кожному, хто робить серйозні конвеєри CI / CD, зробити це. За допомогою сьогоднішніх інструментів JavaScript ми можемо легко створювати / скидати тестові бази даних до і після запуску тестів. Я міг би заперечити, чи підходить цей підхід під час розробки (ви не хочете скидати та створювати свою базу даних при кожній зміні коду), але для цього існує інше рішення. Принаймні, це вирішує проблему необхідності підтримувати окремі інтеграції плагінів, які висміюють дані та приклеюють їх до вашого тестового середовища.
Нікі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.