Модульное тестирование моделей Mongoose в отдельных файлах вызывает проблемы (с использованием Mockgoose & Lab)

Всякий раз, когда модель Mongoose пытается загрузить после того, как она уже загружена, выдается ошибка, например:

ошибка: uncaughtException: не может перезаписать Account Модель однажды скомпилирована. дата = пт 26 февраля 2016 10:13:40 GMT-0700 (MST), pid=19231, uid=502, gid=20, cwd=/Users/me/PhpstormProjects/project, execPath=/usr/local/Cellar/ узел /0.12.4/bin/ узел, версия =v5.2.0, argv=[/usr/local/Cellar/ узел /0.12.4/bin/ узел, /usr/local/Cellar/node/0.12.4/bin/lab], rss=73306112, heapTotal=62168096, heapUsed=29534752, loadavg=[1.6005859375, 1.84716796875, 1.8701171875], время работы =648559 OverwriteModelError: Невозможно перезаписать Account Модель однажды скомпилирована.

С этим у меня все в порядке, но теперь, когда я пишу юнит-тесты для своих моделей, я столкнулся с проблемой.

Просто некоторая базовая информация о файловой структуре...

У меня есть все модели Mongoose в отдельных файлах, расположенных внутри src/models/ папку, и для загрузки этих моделей, просто нужно требовать папку, передавая Mongoose возражать против этого, и src/models/index.js Файл загрузит все модели и вернет объект моделей. index.js файл можно увидеть здесь (и не то, чтобы он относился к делу, но имена моделей - это, в основном, имя файла, без .js)

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

Начальная проблема

Я только что создал 2-й файл тестового модуля, и когда я выполняю каждый из них независимо, они работают просто отлично. Но когда я выполняю все из них, я получаю вышеупомянутую ошибку, заявляя, что я пытаюсь загрузить модели более одного раза. Который, так как мне требуется ./models в каждом модульном тесте я загружаю их более одного раза.

Первая попытка разрешения

Я подумал, что, возможно, я смогу очистить все загруженные модели черезafter()в каждом отдельном файле модульного теста, вот так:

after(function(done) {
    mongoose.connection.close(function() {
        mongoose.connection.models = {}
        done()
    })
})

Который не работал вообще (нет новых ошибок, но тот жене может перезаписатьAccountмодель однажды скомпилированная ошибка (и) сохранилась)

Вторая попытка разрешения (полууспешная)

Вместо того, чтобы модели выдавали ошибку в последней строке, когда она пытается вернуть Mongoose.model()Я вставляю некоторую логику в верхнюю часть модели, чтобы проверить, загружена ли модель, и если да, вернем этот объект модели:

const thisFile  = path.basename( __filename ).match( /(.*)\.js$/ )[ 1 ]
const modelName = _.chain( thisFile ).toLower().upperFirst().value()

module.exports = Mongoose => {
    // Return this model, if it already exists
    if( ! _.isUndefined( Mongoose.models[ modelName ] ) )
        return Mongoose.models[ modelName ]

    const Schema = Mongoose.Schema

    const appSchema = new Schema( /* ..schema.. */)

    return Mongoose.model( modelName, appSchema )
}

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

Новая проблема

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

$ lab

  ..................................................
  ...

Test script errors:

Cannot set property '0' of undefined
      at emitOne (events.js:83:20)
      at EventEmitter.emit (events.js:170:7)
      at EventEmitter.g (events.js:261:16)
      at emitNone (events.js:68:13)
      at EventEmitter.emit (events.js:167:7)

Cannot set property '0' of undefined
      at emitOne (events.js:83:20)
      at EventEmitter.emit (events.js:170:7)
      at EventEmitter.g (events.js:261:16)
      at emitNone (events.js:68:13)
      at EventEmitter.emit (events.js:167:7)

Cannot set property '0' of undefined
      at emitOne (events.js:83:20)
      at EventEmitter.emit (events.js:170:7)
      at EventEmitter.g (events.js:261:16)
      at emitNone (events.js:68:13)
      at EventEmitter.emit (events.js:167:7)

There were 3 test script error(s).

53 tests complete
Test duration: 1028 ms
No global variable leaks detected

В этой трассировке стека не слишком много подробностей.

Я не уверен, вызвано ли это кодом, который я добавил в каждую модель, проверяя, загружена ли она уже, если это так, то он либо обнаружится, когда я выполню одиночный модульный тест, либо покажет, что Cannot set property '0'из неопределенного дважды (сначала для успешной начальной загрузки модели, затем дважды для следующих двух... я думаю)

Если у кого-то есть вклад, я был бы очень признателен! Спасибо

Обновления

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

Кроме того, я использую Winston, чтобы сделать мою регистрацию. Если я изменю уровень журнала на отладочный, который показывает много записей отладки в консоли, он не показывает никаких записей об этих ошибках... Так что я думаю, что это может быть вызвано не моими сценариями, а чем-то в модульном тестировании зависимостей?

Ошибки говорят, что они происходят из файла error.js, но больше ничего не говорят. Я пытался найти error.js через find . -name 'events.js', без результатов.. Странно

1 ответ

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

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

Похоже, что у вас есть проблема, аналогичная той, которая обсуждается в этом выпуске, - OverwriteModelError с мокко 'watch'.

Есть несколько решений, которые стоит попробовать:

1) Создайте новое соединение мангуста каждый раз:

var db = mongoose.createConnection()

2) Запустите мокко через nodemon. Это выглядит для меня загадочно, но все же стоит попробовать, может быть, каждый тест будет проходить совершенно независимо. Я также предполагаю, что вы используете мокко для тестов:

nodemon --exec "mocha -R min" test

3) Очистить модели и схемы мангусты после каждого теста:

after(function(done){
  mongoose.models = {};
  mongoose.modelSchemas = {};
  mongoose.connection.close();
  done();
});
Другие вопросы по тегам