NodeJS 如何测试一个函数是否调用了特定的方法/函数?

anhgbhbe  于 2023-05-06  发布在  Node.js
关注(0)|答案(2)|浏览(252)

在Mocha中有没有一种方法来测试一个函数是否调用了一个特定的方法或外部函数?

  • 我正在使用Mocha和Chai,但我对任何其他Assert库都持开放态度。*

好的,所以使用sinon来测试methid是否被调用是非常容易的。我不确定是否要测试是否调用了外部函数。因此,我更新了示例,以表示更“真实的”的东西。我正在开发一个node应用程序,所以foo.jsbar.js都是模块。

示例:

foo.js

var bar = require('bar');
var xyz = function () {};

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

bar.js

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

fooSpec.js

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 () {
    // ????????????
  });
});

因此,正如您所看到的,我已经找到了如何测试Foo.prototype.bar的方法,但是我找不到实现第二个和第三个测试的方法。

yfwxisqw

yfwxisqw1#

所以这个问题真的是二合一。

首先,“如何测试方法是否被调用”:我在示例中列出了这方面的代码,但基本上,使用sinon.js,您只需将方法 Package 在“spy”中,这允许您编写一个测试,期望该spy已被调用。
其次,“如何测试私有函数(未作为模块的一部分导出的函数)是否被调用”:

基本上,你不知道。在测试环境中而不是在生产环境中导出这些函数是可能的,但这对我来说似乎有点太古怪了。
我得出的结论是,当调用另一个模块时,你应该打破TDD周期,而不是测试这个,因为它可能会是一个小的代码量,模块已经被测试过了。
如果你正在调用一个在你的模块中声明的私有函数,并且想要测试它,你应该编写一个更广泛的测试来测试这个函数被调用的结果,而不是测试这个函数是否被调用或者在这个函数中实际发生了什么。
这里有一个非常简单的例子:

foo.js

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'
  }
};

fooSpec.js

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');

  });

};
nhaq1z21

nhaq1z212#

现在已经过时了。API不同。我将留下回应,因为推理仍然是最新的。

我在Mocha中使用expectAssert库,但Chai可能有类似的方法

第一个

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

您正在测试的代码的问题是上下文。所以我会在这个答案中解决这个问题。您可以测试是否调用了外部函数,但它需要上下文,因此您可能必须更改代码。
我使用bar(模块)作为示例。对于xyz(函数),转到第二种方法。对两者的解释是一样的。

1.导出对象内部的bar

bar.js

var bar = module.exports = { 
  bar: function () {}; 
}

foo.js

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

这样你就可以监视它做:

fooSpec.js

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();

2.设置bar模块为Foo的prototype方法

如果你不想改变bar.js,你可以将所需的模块设置为Foo的原型方法。然后你就有了一个可以监视的背景。

foo.js

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

fooSpec.js

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 () {};

在此代码段中,您需要使用Foo.prototype设置this.bar。那么,如何设置两个同名的变量并很好地相互引用呢?
答案是语境和范围。您的this.bar正在引用this上下文中设置的bar变量(指向Foo)。另一方面,您的bar(注意没有this)引用了函数(模块)作用域中的bar变量集。
所以,你可以测试你的Foo.prototype.bar,因为它是一个模块方法,有上下文,你可以监视它。购买你不能窥探所需的bar,因为它是有作用域的(认为它是私有的)。
阅读:http://ryanmorr.com/understanding-scope-and-context-in-javascript/

相关问题