简体   繁体   English

undefined不是函数:单元测试护照身份验证自定义回调

[英]undefined is not a function: unit testing passport authentication custom callback

I'm new to passport and express and trying to get a better idea of how everything works together by creating unit tests for all of my code. 我刚接触护照并表达意见,并试图通过为我的所有代码创建单元测试来更好地了解一切如何协同工作。 I have been having good success but today ran into an issue I don't quite understand... 我一直都取得成功,但今天遇到了一个我不太了解的问题...

I'm attempting to unit test the following exported function on session.js : 我正在尝试对session.js上的以下导出功能进行单元测试:

'use strict';

var mongoose = require('mongoose'),
passport = require('passport');

exports.login = function (req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    var error = err || info;
    if (error) return res.json(401, error);

    req.logIn(user, function(err) {

      if (err) return res.send(err);
      res.json(req.user.userInfo);
    });
  })(req, res, next);
};

I seem to be having trouble with the second to last line (req, res, next) and how/when it gets called. 我似乎在倒数第二行(req,res,next)以及如何/何时调用它方面遇到麻烦。 I also have never seen this type of call in Javascript where the last line is just a set of parameters. 我也从未在Javascript中看到过这种类型的调用,其中最后一行只是一组参数。

In order to test I'm using rewire , sinon, and mocha. 为了测试我使用的是重新布线 ,兴农,和摩卡。 In my test I'm using rewire to change the passport dependency to a mock object that I control. 在我的测试中,我使用重接线将护照依赖关系更改为我控制的模拟对象。

My test seems to be working as expected as evidenced by where it is failing and what instanbul is telling me is covered but it alwasy throws: TypeError: undefined is not a function . 我的测试似乎在按预期方式工作,如失败的地方以及instanbul告诉我的内容所涵盖,但它总是抛出: TypeError: undefined is not a function

If I comment out the (req, res, next) line in session.js then my test actually runs successfully. 如果我注释掉session.js(req,res,next)行,则我的测试实际上可以成功运行。

My test session.unit.js : 我的测试session.unit.js

'use strict';

var rewire = require('rewire'),
should = require('should'),
sinon = require('sinon'),
sessionController = rewire('../../../../lib/controllers/session'),
passportMock = {};


describe('Session Controller', function() {

  describe('#login', function(){

    beforeEach(function(){
      sessionController.__set__({
        'passport': passportMock
      });

    });

    it('should return 401 status and error if passport authentication returns error', function(){
      //given
      var res = {
          json: sinon.spy(),
          send: sinon.spy()
        },
        req = {
          logIn: sinon.spy()
        },
        next = sinon.stub();

      passportMock.authenticate = sinon.stub().callsArgWith(1, 'ERROR', null, null);

      //when
      sessionController.login(req, res, next);

      //then
      res.json.calledWith(401,'ERROR').should.be.true;
    });

  });

});

My questions are: 我的问题是:

  1. What is the last line (req, res, next) used for and when is it called? 最后一行是什么(req,res,next),何时调用? (I suspect middleware) (我怀疑中间件)
  2. Is there a way I can change my test to get it to pass without the undefined error? 有没有一种方法可以更改测试以使其通过且不会出现未定义的错误?

Thanks very much for reading and any help you can provide!! 非常感谢您的阅读和提供的任何帮助!!

** EDIT: ** I think I left out a critical piece of information... This session.login function is called from my routes.js file so I believe the last line is needed for middleware to continue. ** 编辑: **我认为我遗漏了重要的信息...从我的routes.js文件中调用了session.login函数,因此我认为中间件继续需要最后一行。 I'm still confused as to how to allow this to continue processing in the unit testing though. 我仍然对如何让它在单元测试中继续进行处理感到困惑。

routes.js snippet: routes.js代码段:

  app.route('/api/session')
    .post(session.login)
    .delete(session.logout);

** EDIT2: ** **编辑2 **

Added the top part of session.js for clarity on how passport is initially declared with require . 添加了session.js的顶部,以清楚说明最初如何使用require声明护照。 In the unit test I am replacing passport via rewire with my mock (stub) object so that I can control what passport returns. 在单元测试中,我通过用模拟(存根)对象通过重接线替换护照,以便可以控制护照返回的内容。

  1. The })(req, res, next); })(req, res, next); towards the end of your session.js is unnecessary because of how scoping rules work in JavaScript and because passport.authenticate does not return a function (it probably returns nothing which by default returns undefined), so that is the reason for the error. 由于JavaScript中的作用域规则是如何工作的,并且因为passport.authenticate不会返回函数(它可能不返回任何东西,默认情况下未返回未定义的函数),因此没有必要在session.js的末尾进行操作,因此这就是错误的原因。

  2. Just change the })(req, res, next); 只需更改})(req, res, next); from the end of session.js to just }); 从session.js的末尾到}); .

I'm not sure if this will help, but this is generally how I stub passport.authenticate when used in the same way you have. 我不确定这是否会有所帮助,但这通常是我以与您相同的方式使用时存根passport.authenticate的方式。

var stub = sinon.stub(passport, 'authenticate').returns(function() {});
stub.yields(new Error('fails here'));

// add your tests here

stub.restore();

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

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