【问题标题】:Nodejs Expressjs Mongodb Javascript Unit Test Using Mocha Chai Sinon for random Nodejs ProjectNodejs Expressjs Mongodb Javascript 单元测试使用 Mocha Chai Sinon 进行随机 Nodejs 项目
【发布时间】:2021-03-08 00:38:08
【问题描述】:

有人可以告诉我如何为函数 homeDog 的这个示例项目执行“单元测试”吗? 我有以下来自随机项目的示例函数,我希望尝试为其添加单元测试,同时我学习如何使用 Mocha Chai Sinon 进行单元测试,引用来自 https://github.com/seanaharrison/node-express-mongodb-example 的示例随机 Nodejs 项目。

我一直在努力为 homeDog 函数进行单元测试,但后来我遇到了问题,有人可以向我展示如何为函数 homeDog 进行单元测试的工作单元测试,以便我有一个起点吗?

这是我尝试过但失败的方法。

exports.homeDog = function(req, res) {
    var db = req.db;
    var collection = db.collection('dogs');
    collection.find().toArray(function(err, dogsArray) {
        if (dogsArray) {
            res.render('index', {
                title: 'Dogs',
                path: req.path,
                dogs: dogsArray
            });
        }
        else {
            res.render('index', {
                title: 'No Dogs Found'
            });
        }
    });
};

【问题讨论】:

    标签: node.js mongodb unit-testing mocha.js sinon


    【解决方案1】:

    由于您需要一个“模拟数据库”,但您没有在代码中使用它(我认为),我将尝试解释如何使用 mock database 测试 API 项目。

    也就是说:您不需要真正的数据库来测试您的 API,您需要在每次执行测试时创建并关闭一个“内存数据库”。

    首先是安装一个模拟依赖项,如mongo-mockmongodb-memory-server 或任何你想要的。

    就个人而言,我使用mongodb-memory-server

    因此,您可以按照文档设置您的项目。我的mockDB.js 文件与test.js 处于同一级别。

    mockDB.jsfile 应该包含类似这样的内容(如果您使用其他包,此代码可能会更改。):

    const { MongoMemoryServer } = require('mongodb-memory-server');
    const mongod = new MongoMemoryServer();
    
    module.exports.connect = async () => {
        const uri = await mongod.getUri();
    
        const mongooseOpts = {
            useNewUrlParser: true,
            useFindAndModify: false,
            useUnifiedTopology: true 
        };
    
        await mongoose.connect(uri, mongooseOpts);
    }
    

    然后,您有一个文件,您的mock DB 将在其中被初始化和连接。 至此,我的mongo DB就被初始化了。我正在使用mongoose,但允许使用其他选项。

    控制器(我认为在这种情况下为homeDog)文件在这里并不重要,因为您正在测试控制器,因此代码必须与生产中的代码相同。 控制器是要测试的代码,因此不应出于测试目的对其进行修改。

    最后一个文件是test.js。 在此文件中,您必须导入您的 mockDB.js 文件并启动 de 数据库。

    const mockDB = require('./mockDB');
    
    ... 
    
    before(async () => await mockDB.connect());
    

    通过这种方式,您可以执行您的测试,控制器将对memory database 执行查询。另外,您可以使用您的文件mockDB.js 来实现辅助查询。

    例如,要从字段中获取特定值,您可以创建类似的方法

    module.exports.findValueById(id) => {
      //return result
    }
    

    在你的测试文件中调用这个模块:

    var idFound = mockDB.findValueById(id)
    

    使用它,例如,您可以在插入文档后查询数据库并检查集合是否正常。或者检查更新是否正确或任何你想要的。

    如果您的函数是GET,您只需将homeDog 返回的数据与现有的“模拟数据库”进行比较。

    【讨论】:

    • 我的意图是创建一个单元测试,如果我通过询问如何模拟数据库而弄错了你,对不起。因为我看到的功能都与mongodb有关。但我不能测试它隔离。我在想如何为 homeDog 函数创建一个单元测试。感谢您对 mongodb 模拟的参考。
    • 稍后我会更新我的答案,添加一个测试用例示例,抱歉。但是homeDog() 是我认为您使用数据库连接的端点。所以我想你会需要这部分。
    【解决方案2】:

    您提到了单元测试,这意味着它应该是一个独立的测试(没有真正调用数据库)。为此,您需要包含 Sinon 来模拟一些函数。

    一些要模拟的函数:

    1. db.collection
    2. collection.find().toArray()
    3. res.render
    // include the sinon library
    const sinon = require('sinon');
    
    // include the source file that contain `homeDog` function
    const src = require('./src');
    
    describe('test', () => {
      it('returns index with title, path and dogs if dogs array exist', () => {
        const dogs = ['doggy', 'dogg2'];
    
        // define mock `req` parameter
        const mockReq = {
          path: 'whatever',
          db: {        
            collection: sinon.stub().returnsThis(), // `returnsThis` to mock chained function
            find: sinon.stub().returnsThis(),
            toArray: sinon.stub().callsFake(callback => {
              callback(null, dogs) // specify dogs array here
            })
          }
        };
    
        // define mock `res` parameter
        const mockRes = {
          render: sinon.stub(),
        }
    
        src.homeDog(mockReq, mockRes); // pass the mock req and mock res to homeDog
    
        // check whether the function is called correctly
        sinon.assert.calledWith(mockReq.db.collection, 'dogs');
        sinon.assert.calledWith(mockRes.render, 'index', { title: 'Dogs', path: 'whatever', dogs });
      })
    
      it('returns index with title', () => {
        const mockReq = {
          path: 'whatever',
          db: {        
            collection: sinon.stub().returnsThis(),
            find: sinon.stub().returnsThis(),
            toArray: sinon.stub().callsFake(callback => {
              callback(null, null) // give null value for dog array
            })
          }
        };
    
        const mockRes = {
          render: sinon.stub(),
        }
    
        src.homeDog(mockReq, mockRes); 
    
        sinon.assert.calledWith(mockRes.render, 'index', { title: 'No Dogs Found' });
      })
    })
    

    结果

      test
        ✓ returns index with title, path and dogs if dogs array exist
        ✓ returns index with title
    
    
      2 passing (12ms)
    

    【讨论】:

      猜你喜欢
      • 2017-10-08
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 2021-09-27
      • 1970-01-01
      • 2023-04-11
      相关资源
      最近更新 更多