Unit Test с помощью Mongoose

Я новичок в Node.js, Mongoose и тестировании в этой среде. У меня есть следующая схема, объявленная в отдельном файле.

Issue = mongoose.model("Issue", {
  identifier: String,
    date: String,
    url: String,    
    name: String,
    thumbnailURL: String
});

Затем у меня есть этот метод, который просто возвращает все экземпляры Issue в коллекции MongoDB.

function issues(request, response) {
  response.setHeader('Content-Type', 'text/json');

  Issue.find().sort('date').exec(function(error, items) {
    if (error) {
      response.send(403, {"status": "error", "error:": exception});
    }
    else {
      response.send(200, {"issues": items});
    }
  });
}

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

  • Правильно ли эта функция правильно задает тип контента.
  • Выполняет ли сортировка функции поле date
  • Возвращает ли функция 403 при возникновении ошибки?
  • ... и т.д.

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

Ответы

Ответ 1

Использование мокки с chaijs и sinonjs в моем коде node для меня работает что-то вроде этого метода:

var should = require('chai').should(),
sinon = require('sinon'),
mongoose = require('mongoose');

it('#issues() handles mongoosejs errors with 403 response code and a JSON error message', function (done) {

// mock request
var request = {};

// mock response
var response = {};
response.setHeader = function(header) {};
response.send = function (responseCode, jsonObject) {
    responseCode.should.equal(403);
    jsonObject.stats.should.equal('error');
    // add a test for "error:": exception
    done();
}

var mockFind = {
    sort: function(sortOrder) {
        return this;
    },
    exec: function (callback) {
        callback('Error');
    }
}

// stub the mongoose find() and return mock find 
mongoose.Model.find = sinon.stub().returns(mockFind);

// run function
issues(request, response);

});

Ответ 2

Mongoose model (ваш Issue) возвращает новый экземпляр объекта Query. Новый экземпляр Query имеет доступ к методу exec через prototype. (мангуста 3.8 ~)

Если вы хотите вернуть ошибку, вы можете написать:

sinon.stub(mongoose.Query.prototype, "exec").yields({ name: "MongoError" }, null);

Ответ 3

Я не уверен, как тестировать Content-Type, и я сам не тестировал этот код, но я рад помочь, если он не работает. Кажется, это имеет смысл для меня. В принципе, мы просто создали обратный вызов, чтобы мы могли перемещать response.send из собственной пользовательской логики, после чего мы можем протестировать этот обратный вызов. Дайте мне знать, если это не работает или имеет смысл. Вы можете использовать ссылки, которые другие ребята размещали, чтобы не допустить подключения к db.

Issue = mongoose.model("Issue", {
    identifier: String,
    date: String,
    url: String,    
    name: String,
    thumbnailURL: String
  });

  function issues(callback, request, response) {
    Issue.find().sort('number').exec(function(error, items) {
      if (error) {
        callback(403, {"status": "error", "error:": exception});
      }
      else {
        callback(200, {"issues": items});
      }
    });
  }

  //Note: probably don't need to make a whole new `sender` function - depends on your taste
  function sender(statusCode, obj) {
    response.setHeader('Content-Type', 'text/json');
    response.send(statusCode, obj);
  }

  //Then, when you want to implement issues
  issues(sender, request, response);

  //The tests - will depend on your style and test framework, but you get the idea
  function test() {
    //The 200 response
    issues(function(code, obj) {
      assert(code === 200);
      assert(obj.issues === ??);   //some testable value, or just do a truthy test
      //Here, you can also compare the obj.issues item to the proper date-sorted value
    });

    //The error response
    issues(function(code, obj) {
      assert(code === 403);
      assert(code.status === 'error');
    });
  }

Ответ 4

Хорошим местом для начала было бы:

  • Изучите понятия вокруг заглушек и макетов и проверьте двойники.
  • Отъезд Sinon.js, который является предпосылкой выбора для Node.JS