【问题标题】:Unit Test with Mongoose使用 Mongoose 进行单元测试
【发布时间】:2013-10-17 12:44:24
【问题描述】:

我是 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 模式对象作为参数,但感觉不对。有人有更好的建议吗?

【问题讨论】:

  • 你可能想从下面选择一个答案作为接受;)

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


【解决方案1】:

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

如果你想返回一个错误你可以这样写:

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

【讨论】:

    【解决方案2】:

    在我的节点代码中将 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);
    
    });
    

    【讨论】:

      【解决方案3】:

      我不确定如何测试 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');
          });
        }
      

      【讨论】:

        【解决方案4】:

        一个好的起点是:

        1. 研究stubs and mocks 周围的概念,并测试替身。
        2. 查看Sinon.js,它是 Node.JS 选择的 Mocking 框架

        【讨论】:

        • 完全 - 我了解什么是模拟以及如何使用它们,但是如何将模拟放入 issues 方法中?或者是否有必要将该逻辑提取到另一个方法中,将Issue 模式作为参数传递(然后在我的测试中模拟模式)?
        • 我会提取两个方法 onSuccessonError 包含响应调用,然后设置一个期望,当 Issue.exec 被存根以回调为 false 时调用每个方法等等。
        • 您可能会发现这对您问题的其他部分很有用:stackoverflow.com/questions/8021956/…
        猜你喜欢
        • 2014-05-17
        • 2023-04-01
        • 2016-05-30
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 2011-11-16
        • 2015-05-28
        • 2012-05-23
        相关资源
        最近更新 更多