Javascript 如何测试函数是否调用特定的方法/函数?

Javascript 如何测试函数是否调用特定的方法/函数?,javascript,node.js,tdd,mocha.js,chai,Javascript,Node.js,Tdd,Mocha.js,Chai,在Mocha中是否有一种方法可以测试函数是否调用特定的方法或外部函数 我在Chai使用摩卡,但我对任何其他断言库开放 好的,所以使用sinon测试methid是否被调用非常容易。不过,我不确定是否要进行测试以查看是否正在调用外部函数。因此,我更新了示例,使其更能代表“真实世界”。我正在开发一个节点应用程序,所以foo.js和bar.js都是模块 例子: foo.js bar.js fooSpec.js 正如你所见,我已经知道了如何测试Foo.prototype.bar,但是我找不到实现第二个和

在Mocha中是否有一种方法可以测试函数是否调用特定的方法或外部函数

我在Chai使用摩卡,但我对任何其他断言库开放


好的,所以使用sinon测试methid是否被调用非常容易。不过,我不确定是否要进行测试以查看是否正在调用外部函数。因此,我更新了示例,使其更能代表“真实世界”。我正在开发一个节点应用程序,所以
foo.js
bar.js
都是模块

例子: foo.js bar.js fooSpec.js
正如你所见,我已经知道了如何测试
Foo.prototype.bar
,但是我找不到实现第二个和第三个测试的方法。

所以这个问题实际上是二合一的

首先,“如何测试是否调用了方法”: 我在示例中列出了这方面的代码,但基本上,使用sinon.js,您只需将该方法包装在一个“spy”中,这样您就可以编写一个测试,期望调用该spy

其次,“如何测试私有函数(未作为模块的一部分导出的函数)是否已被调用”:

基本上,你没有。当在测试环境中而不是在生产环境中时,可以导出这些函数,但这对我来说似乎有点太粗糙了

我得出的结论是,当调用另一个模块时,您应该打破TDD循环,而不是对此进行测试,因为它可能只需要少量代码,并且模块本身已经过测试

如果您正在调用在您的模块中声明的私有函数并希望对其进行测试,那么您应该编写一个更广泛的测试来测试调用该函数的结果,而不是测试函数是否正在被调用或函数中实际发生了什么

下面是一个非常简单的例子:

foo.js fooSpec.js
我正在使用
expect
断言库和
Mocha
,但是
Chai
可能有类似的方法


弗斯特 您可以使用Spies测试函数是否调用特定的方法/函数。您在上面的代码中做到了这一点

第二 您正在测试的代码的问题是上下文。因此,我将在这一回答中解决这一问题。您可以测试是否调用了外部函数,但它需要一个上下文,因此您可能需要更改代码

我使用的是
bar
(模块)作为示例。对于
xyz
(函数),转到第二种方法。两者的解释是相同的

1.导出对象内部的
条形图
bar.js foo.js 通过这种方式,您可以通过以下方式监视它:

fooSpec.js 2.将
bar
模块设置为Foo的原型方法 如果不想更改
bar.js
,可以将所需的模块设置为Foo的原型方法。那么你就有了一个可以监视的上下文

foo.js fooSpec.js
解释 您必须做的更改是为了更改变量的上下文

为了说明这一点:

var bar = require('bar');

var Foo = module.exports = function () {
  this.bar();
  bar();
};
Foo.prototype.bar = function () {};
在这个代码段中,您需要
bar
以及以后使用
Foo.prototype
设置
this.bar
。那么,如何设置两个同名的变量并很好地相互引用呢

答案是上下文和范围。您的
this.bar
正在引用
this
上下文中设置的
bar
变量(该变量指向
Foo
)。另一方面,您的
-注意没有
-引用函数(模块)范围中设置的
变量

因此,您可以测试
Foo.prototype.bar
,因为它是一个模块方法,有一个上下文,您可以监视它。Buy你不能窥探所需的
,因为它的作用域是有限的(可以认为它是私有的)


读得好:

如果你的代码片段是模块,那么展示你从模块中导出的意思会很有帮助,因为它关系到你将得到的答案的类型。我更新了这个示例的更多细节。示例文件是节点应用程序中的模块。这很有帮助,因为我一直在努力测试是否正确编写测试,只需查看在初始化组件时是否调用了某些函数,并想知道这是否真的有用。但是从你所说的来看,实际上最好测试调用该函数的结果是否发生,因为简单地验证调用了某个特定名称的东西实际上并不能增加事情正常运行的信心。如果它还包含一个间谍示例,这将是一个很好的答案。TohaveBeenCall是一个玩笑方法,因此在摩卡咖啡中无效
var bar = module.exports = function () {};
var chai      = require('chai');
var sinon     = require('sinon');
var sinonChai = require('sinonChai');
var expect    = chai.expect;
var Foo       = require('../lib/foo');

chai.use('sinonChai');

describe('Foo', function () {

  var method;

  beforeEach(function (done) {
    method = sinon.spy(Foo.prototype, 'bar');
    done();
  });
  afterEach(function (done) {
    method.restore();
    done();
  });

  it('should call Foo.prototype.bar() immediately', function () {

    new Foo();
    expect(method).to.have.been.called;
    
  });

  it('should call the module bar immediately', function () {
    // ????????????
  });

  it('should call xyz() immediately', function () {
    // ????????????
  });
});
var _ = require('lodash');

var Foo = module.exports = function (config) {

  this.config = _.merge({
      role: 'user',
      x: '123',
      y: '321'
    },
    config);

  this.config.role = validateRole(this.config.role);
};

var validateRole = function (role) {
  var roles = [
    'user', 'editor', 'admin'
  ];

  if (_.contains(roles, role)) {
    return role;
  } else {
    return 'user'
  }
};
var chai = require('chai');
var expect = chai.expect;
var Foo = require('../lib/foo');

describe('Foo', function () {

  it('should set role to \'user\' if role is not valid', function () {

    var foo = new Foo({role: 'invalid'});
    expect(foo.config.role).to.equal('user');

  });

};
var bar = module.exports = { 
  bar: function () {}; 
}
var Foo = module.exports = function () {
  bar.bar();
  ....
};
it('should call the module bar immediately', function () {

  //note I'm getting the bar method from the exported object (bar module)
  var bar = expect.spyOn(bar, 'bar'); 

  new Foo();

  expect(bar).toHaveBeenCalled();
var bar = require('./bar');

var Foo = module.exports = function () {
  this.bar();
  this.barModule();
};
Foo.prototype.bar = function () {};
Foo.prototype.barModule = bar; // setting here as barModule
it('should call the module bar immediately', function () {
  var barSpy = expect.spyOn(Foo.prototype, 'barModule');

  new Foo();

  expect(barSpy).toHaveBeenCalled();    
});
var bar = require('bar');

var Foo = module.exports = function () {
  this.bar();
  bar();
};
Foo.prototype.bar = function () {};