我目前正在使用mocha,chai和sinon测试此代码

import passport   from 'passport';
import jwt        from 'jsonwebtoken';
import expressJwt from 'express-jwt';
import compose    from 'composable-middleware';

import User       from '../apis/user/user.model';
import config     from '../../config/app';

const validateJwt = expressJwt({
  secret: config.auth.secret
});

export function signToken(id, role) {
  return jwt.sign({ id, role }, config.auth.secret, {
    expiresIn: config.auth.expiresIn
  });
}

export function setTokenCookie(req, res) {
  if (!req.user)
    return res.status(404)
      .json({
        message: "It looks like you aren't logged in, please try again"
      });

  const token = signToken(req.user.id, req.user.role);
  res.cookie('token', token);
  res.redirect('/');
}

export function isAuthenticated() {
  return compose()
    .use((req, res, next) => validateJwt(req, res, next))
    .use((req, res, next) => {
      User.get(req.user.id)
        .then(user => {
          req.user = user;
          next();
        }, () => {
          return res.status(404).json({
            message: 'User not found, please try to login again'
          });
        })
        .catch(err => next(err));
    });
}

export function hasRole(role) {
  return compose()
    .use(isAuthenticated())
    .use((req, res, next) => {
      if (req.user.role === role) {
        next();
      } else {
        res.status(403).json({ 
          message: "You don't have the right privilege to access this resource"
        });
      }
    });
}

这是测试文件

import request            from 'supertest';

import app                from '../main';
import User               from '../apis/user/user.model';
import { hasRole } from './auth.service';

describe('Auth Service', () => {
  let user, admin;

  before(done => {
    const _user = {
      username: 'user',
      email: 'user@user.com',
      password: 'user'
    };

    const _admin = {
      username: 'admin',
      email: 'admin@admin.com',
      password: 'admin',
      role: 'admin'
    };

    User.delete().execute()
      .then(() => {
        return User.save([_user, _admin]);
      })
      .then(users => {
        user = users[0];
        admin = users[1];

        done();
      });
  });

  after(done => {
    User.delete().execute()
      .then(() => done());
  });

  describe('hasRole', () => {

    it('should call res.status with 403 and send message if the user does not have the right access', done => {
      const token = signToken(user.id, user.role);
      const reqStub = {
        headers: {
          authorization: `Bearer ${token}`
        }
      };

      const statusSpy = spy();
      const jsonSpy = spy();

      const resStub = {
        status(statusCode) {
          statusSpy(statusCode);

          return {
            json: jsonSpy
          };
        }
      };

      const nextSpy = spy();

      Object.observe(statusSpy, changes => {
        if (changes[0].name === 'called') {
             expect(statusSpy.args[0][0]).to.equal(403);

          expect(jsonSpy).to.have.been.calledOnce;
          expect(jsonSpy.args[0][0].message).to.equal("You don't have the right privilege to access this resource");

          done();
}
      });

      hasRole('admin')(reqStub, resStub, nextSpy);

      // This particular test sometimes does not work
      // This setTimeout is just a reminder 
      setTimeout(() => {
        done(new Error('Sometimes this does not work, please investigate'));
      }, 1500);
    });
  });
});

我运行此测试,50%的时间通过,50%的时间失败 . 当它出错并且我在Object.observe回调函数中的console.log时,它甚至都没有记录 .

如果Object.observe方法不起作用,那么测试此函数hasRole的最佳方法是什么,而不重构函数本身 . 理想情况下,我想要像spy.on('被叫')这样的东西,但是sinon没有那个