如何测试控制器中是否正在调用方法?

问题描述 投票:3回答:2

这是一个关于使用Mocha在Sails JS中进行异步测试的问题。

我正在使用supertest库在Sails JS中编写控制器测试。 我想检查是否在HTTP POST上调用了一个方法给我们的控制器。 为此,我正在对方法进行存根,并期望在end()调用它,如下所示:

request(sails.hooks.http.app)
    .post('heartbeat/create')
    .send('device: 1')
    .end(function(err, res) {
        expect(publishCreateStub.called).to.be.true;
        done();
    });

当我运行它时,期望失败,因为在断言时不调用该方法。 但是当我按照以下方式将期望放在setTimeout中时,它可以工作:

request(sails.hooks.http.app)
    .post('heartbeat/create')
    .send('device: 1')
    .end(function(err, res) {
        setTimeOut(function() {
            expect(publishCreateStub.called).to.be.true;
            done();
        }, 1000);
    });

有没有办法让测试通过没有setTimeout

这是我正在测试的代码部分: HeartbeatController #create

您还可以通过发送拉取请求来帮助我们解决问题: https//github.com/multunus/one-mdm/issues/1

javascript node.js sails.js mocha supertest
2个回答
3
投票

实际问题是您的控制器不会等待调用publishCreate 。 因此,您正在使用201 Created进行响应,而不检查是否已创建任何内容。

Heartbeat.findOneHeartbeat.publishCreate可能会失败,但你会更新。

要解决此问题,您应该修改控制器,在Heartbeat promise回调中移动响应部分:

create: function (req, res, next) {
  if(req.isSocket) {
    Heartbeat.watch(req);
  }

  Heartbeat.create(req.body)
    .exec(function(error, heartbeat) {
      if(error) {
        res.status(422);
        return res.send('Invalid heartbeat data');
      }

      Heartbeat.findOne(heartbeat.id).populate('device').then(function(newHeartbeat) {
        Heartbeat.publishCreate(newHeartbeat.device);
      }).then(function() {
        // success
        res.status(201);
        res.json({
          device: heartbeat.device
        });
      }, function(err) {
        // something bad happened
        next(err);
       });

    });
}

在我的示例中,我将实际的错误处理委托给下一个快速错误处理中间件:

next(err);

但您可能决定自己处理错误,例如:

res.status(400);
res.send('Can not publish Heartbeat create');

1
投票

您的问题不在您的测试中,它在您的应用程序中:

Heartbeat.create(req.body)
  .exec(function(error, heartbeat) {
    if(error) {
      res.status(422);
      return res.send('Invalid heartbeat data');
    }        

    Heartbeat.findOne(heartbeat.id).populate('device').then(function(newHeartbeat) {
      Heartbeat.publishCreate(newHeartbeat.device);
    });

    res.status(201);
    return res.json({
      device: heartbeat.device
    });
  });
}

https://github.com/multunus/one-mdm/blob/master/api/controllers/HeartbeatController.js

在这里,你创造了一个承诺,但没有回报这个承诺。 因此,在继续之前,您无法等待承诺履行(或错误)。

如果不更详细地了解您的应用程序,我不确定该修复程序。 我会将中间的位抽象为服务*,然后您的HeartbeatController测试可以检查服务是否被调用(同步),并且您对服务的测试可以执行使用promise的异步部分。

*更新:通过“服务”,我的意思是抽象它远离HTTP的任何问题,因此它不知道请求或响应对象。 最终结果是您已经从管理Heartbeat对象的部分解开了HTTP部分(控制器)。 这使得两个部件更容易进行单元测试。

© www.soinside.com 2019 - 2024. All rights reserved.