使用Mongoose进行单元测试

时间:2013-10-09 22:56:09

标签: node.js mongodb unit-testing mongoose jasmine

我是Node.js,Mongoose的新手,并在此环境中进行测试。我在单独的文件中声明了以下架构。

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

然后我有这个方法只返回MongoDB集合中的所有Issue个实例。

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?
  • ......等等

我很想知道如何重构现有代码以使其更具单元可测试性。我已经尝试过创建第二个被调用的函数,接受responseItem模式对象作为参数,但感觉不对。有谁有更好的建议?

4 个答案:

答案 0 :(得分:8)

Mongoose model(您的Issue)返回Query对象的新实例。新的query实例可以通过exec访问prototype方法。 (猫鼬3.8~)

如果要返回错误,可以写:

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

答案 1 :(得分:6)

在我的节点代码中使用mocha和chaijs和sinonjs这样的方法对我有用:

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 :(得分:1)

我不确定如何测试Content-Type,我自己也没有测试过这段代码,但如果它不起作用我很乐意帮忙。这似乎对我有意义。基本上我们只是创建了一个回调函数,因此我们可以将response.send移出实际的自定义逻辑,然后我们可以通过该回调进行测试。如果它不起作用或有意义,请告诉我。您可以使用其他人发布的链接来防止必须连接到数据库。

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');
    });
  }

答案 3 :(得分:0)

一个好的起点是:

  1. 调查stubs and mocks周围的概念,并测试双打。
  2. 查看Sinon.js这是Node.JS的首选Mocking框架