简体   繁体   English

来自服务的控制器解析承诺的Mocha单元测试

[英]Mocha Unit Testing of Controller resolving promise coming from services

I have controller : 我有控制器:

 function(req, res) { // Use the Domain model to find all domain CIO.find(function(err, CIOs) { if (err) { response = responseFormat.create(false, "Error getting CIOs", err, {}); res.status(400).json(response); } else { var metrics = { "count": CIOs.length }; // .then means it will wait for it to finish, then let you have the result var promises = []; for (i in CIOs) { promises.push(Analysis.structureMetrics(CIOs[i].toObject())) } var output = [] var errors = [] Q.allSettled(promises) .then(function(results) { for (i in results) { if (results[i].state === "rejected") { console.log(results[i]) errors.push(results[i].reason.errors) output.push(results[i].reason) } else { output.push(results[i].value) } } }).then(function() { response = responseFormat.create(true, "List of all CIOs", output, metrics, errors); res.status(200).json(response); }) } }); }; 

and cio.test file : 和cio.test文件:

 describe('/cio', function() { describe('GET', function() { //this.timeout(30000); before(function() { }); it('should return response', function(done) { var response = http_mocks.createResponse({eventEmitter: require('events').EventEmitter}) var request = http_mocks.createRequest({ method: 'GET', url: '/cio', }) //var data = JSON.parse( response._getData() ); response.on('end', function() { response.statusCode.should.be.equal(400); done(); }) cioCtrl.getCIOs(request, response); }); }); }); 

getting Error 出现错误

Error: timeout of 10000ms exceeded. 错误:超时超过10000ms。 Ensure the done() callback is being called in this test 确保在此测试中调用了done()回调

1>I have already tried increasing the time, but It doesn't work. 1>我已经尝试过增加时间,但是没有用。

2> What I found is response.('end', function(){}) is not getting called, but not sure why 2>我发现的是response.('end', function(){})没有被调用,但是不确定为什么

Any help would be appreciated. 任何帮助,将不胜感激。 Thanks! 谢谢!

Very good approach for unit testing is using the dependency injection . 单元测试的一个很好的方法是使用依赖注入

For this, your controller file should be something like this: 为此,您的控制器文件应如下所示:

module.exports = class MyController {
  constructor(CIO) {
    this._CIO = CIO;
    this.handler = this.handler.bind(this);
  }

  handler(req, res) {
    // your code here using this._CIO
  }
};

Than in your main file, you create instance of controller: 在主文件中,您将创建控制器实例:

const MyController = require('./controllers/my-controller');

// require your CIO, or create instance...
const CIO = require('./CIO');

const myController = new MyController(CIO);

You simply then pass instance of controller, or it's handler function to the place where it will be used. 然后,您只需将控制器实例或它的处理函数传递到将使用它的地方。

Using this approach allows you to test well. 使用这种方法可以使您进行良好的测试。 Assume your 'it' will look something like this: 假设您的“ it”看起来像这样:

it('should work', function(done) {
  const fakeCIO = { 
    find: function() {
      done();
    }
  };
  const myController = new MyController(fakeCIO);
  myController.handler();
});

Basic differences between testing techniques: 测试技术之间的基本区别:

  • unit test - you test one single unit, how it calls functions, makes assignments, returns values 单元测试-您测试一个单元,它如何调用函数,进行赋值,返回值
  • integration test - you add database to your previous test and check how it is stored/deleted/updated 集成测试-将数据库添加到以前的测试中,并检查数据库的存储/删除/更新方式
  • end-to-end test - you add API endpoint to previous integration test and check how whole your flow works 端到端测试-您将API端点添加到先前的集成测试中,并检查整个流程的工作方式

Update: 更新:
Using async/await approach you will be able to test more things using your controller. 使用异步/等待方法,您将能够使用控制器测试更多的东西。 Assume modifying it in something like this: 假设以如下方式修改它:

async function(req, res) {
  try {
    const CIOs = await CIO.find();
    const metrics = {
      "count": CIOs.length
    };
    const promises = CIOs.map(el => Analysis.structureMetrics(el.toObject());

    for(const promise of promises) {
      const result = await promise();
      // do whatever you need with results
    }

  } catch(err) {
    const response = responseFormat.create(false, "Error getting CIOs", err, {});
    res.status(400).json(response);
  }

Using such approach, during unit testing you can also test that your controller calls methods: 使用这种方法,在单元测试期间,您还可以测试您的控制器调用了以下方法:

  • responseFormat.create responseFormat.create
  • Analysis.structureMetrics Analysis.structureMetrics
  • res.status 状态
  • res.json res.json
  • test catch branch to be executed 要执行的测试catch分支

All this is done with fake objects. 所有这些都是使用伪造的对象完成的。 And sure using OOP is not mandatory, it's just a matter of habits, you can do the same using functional style, with closures , for example. 并且确保使用OOP不是强制性的,这只是一个习惯问题,您可以使用函数样式(例如,使用closures )进行相同的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM