调用原函数而非存根函数

4
我在使用Sinon的stub时遇到了问题。当我对retro中的list进行stub处理,而测试运行时,app.get('/retro', retro.list)执行原始函数retro.list而不是stub。由于出现这种情况,测试失败,因为stub的callCount为0。
我更熟悉coffeescript,并且以同样的方式进行了存根处理。我是否没有理解Javascript的作用域,或者require('../routes/retro')如何工作,或者retro在app.js和test.js中不相同。
非常感谢你的帮助和以下代码。
test.js:
var request = require('supertest')
  , retro = require('../routes/retro')
  , app = require('../app')
  , sinon = require('sinon');
require('should'); 

describe('GET /retro', function() {
  // less involved, but maybe stupid to test
  it('should call retro.list', function(done) {
    var stub = sinon.stub(retro, 'list');

    request(app)
      .get('/retro')
      .end(function(err, res){
        stub.callCount.should.equal(1);

        if (err) return done(err);
        done();
      })
  })
})

app.js:

var express = require('express')
  , config = require('./config')
  , routes = require('./routes')
  , retro = require('./routes/retro');

var app = express();
config(app);

app.get('/', routes.index);
app.get('/retro', retro.list);

module.exports = app;

retro.js:

var retro = {
  list: function(req, res){
    console.log('actual called');
    res.send("respond with a resource");
  }
}

module.exports = retro;

retro 返回什么?它是一个普通对象还是一个新创建的实例? - mor
1
尝试这个代码:retro.list.callCount.should.equal(1); - Sushanth --
@mor 我包含了 retro.js,这样你就可以看到它返回的对象。它不是一个实例。我曾考虑过导出一个实例并尝试存根原型,但那也没有很好地工作。 - kmanzana
@Sushanth-- 我尝试了你的建议,但是 sinon.stub(retro, 'list') 返回的存根在 retro.list 上,因此它们是相同的对象,运行该代码会产生相同的问题。不过还是谢谢你的建议。 - kmanzana
2个回答

9

在需要/创建 app 之前,您可能需要先创建您的存根。

var request = require('supertest')
  , sinon = require('sinon')
  , retro = require('../routes/retro');

var stubRetroList = sinon.stub(retro, 'list');

var app = require('../app');

// ...

    stubRetroList.callCount.should.equal(1);

这样可以在传递到路由之前更新retro.list:
app.get('/retro', retro.list);

问题可能是因为 retro.list 没有被以引用传递(指针),而是作为值传递的引用(复制)。因此,虽然 sinon.stub() 修改了 retro.list,但不会影响 '/retro' 路由已经拥有的副本。

谢谢Jonathan!这个代码完美运行。虽然我不太喜欢在那里进行存根,但我很高兴我理解了它是存根引用/副本而不是同一个对象。 - kmanzana
proxyquire是这个问题的更好解决方案。 - kmanzana

1
我遇到了同样的问题,而被接受的答案(虽然正确)并没有帮助。事实证明,为了使sinon存根工作,存根化的方法不能在同一模块中使用。换句话说,存根化模块端点将仅存根化模块端点,而不是被module.exports引用的函数的内部使用。
通过示例解释:

module.js

const express = require('express')
const router = express.Router()

router.get('/', function (req, res) {
  res.status(200).json(list())
})

function list() {
    return ['something']
}

module.exports = {
    router: router,
    list: list
}

module.spec.js

// This stub will not work
sinon.stub(module, 'list').callsFake(() => ['something else'])

为使其正常工作,您需要将要存根的内容分离到其自己的模块中并以此方式使用它:

sub_module.js

function list() {
    return ['something']
}

module.exports = {
    list: list
}

现在可以对sub_module.list()进行桩测试。 (对于OP来说,他在原地定义了一个方法,因此这不是问题)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接