如何testing一个函数是否调用特定的方法/函数?
摩卡里有没有一种方法来testing一个函数是否调用特定的方法或外部函数?
我正在使用摩卡与柴,但我打开任何其他断言库。
好的,用sinon来testing一个方法是否被调用是非常容易的。 我不确定testing,看是否正在调用一个外部函数。 所以我更新了一些例子来代表一些更“真实的世界”。 我正在研究节点应用程序,所以foo.js
和bar.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 () { // ???????????? }); });
所以你可以看到我已经想出了如何testingFoo.prototype.bar
,但我找不到实现第二和第三个testing的方法。
所以这个问题真的是二合一。
首先 ,“如何testing一个方法是否被调用”:我在这个例子中给出了这个代码,但是基本上,使用sinon.js,你只需要用一个“间谍”来包装这个方法,期待那间谍被召唤。
其次 ,“如何testing一个私有函数(不是作为模块的一部分导出的函数)是否被称为”:
基本上,你没有。 在testing环境中而不是在生产环境中导出这些函数是可能的,但是这对我来说似乎有些过于黑暗。
我得出的结论是,当调用另一个模块时,你应该打破TDD循环,而不是testing这个模块,因为它可能只是less量的代码,模块已经被自己testing了。
如果你正在调用在你模块中声明的私有函数,并且想要testing它,你应该写一个更广泛的testing来testing被调用的函数的结果,而不是testing函数是被调用的还是实际的在function内发生。
这是一个非常简单的例子:
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'); }); };
我正在使用expect
与Mocha
断言库,但Chai
可能有类似的方法
第一
你可以testing一个函数是否使用Spies调用特定的方法/函数。 你在上面的代码中做了这个。
第二
您正在testing的代码的问题是上下文。 所以我会在这个答案中解决它。 你可以testing一个外部函数是否被调用,但是它需要一个上下文 ,所以你可能不得不改变你的代码。
我以
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的原型方法
如果您不想更改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(); });
说明
你必须做的改变是改变variables的上下文。
要说清楚:
var bar = require('bar'); var Foo = module.exports = function () { this.bar(); bar(); }; Foo.prototype.bar = function () {};
在这个片段中,你需要bar
,稍后使用Foo.prototype
设置this.bar
。 那么,如何设置2个相同名称的variables并相互引用呢?
答案是上下文和范围。 你的this.bar
引用了在this
上下文中设置的bar
variables(指向Foo
)。 另一方面,你的bar
-note没有this
– 引用在函数的(模块)范围中设置的bar
variables。
所以,你可以testing你的Foo.prototype.bar
,因为它是一个模块方法,有一个上下文,你可以监视它。 买你不能窥探所需的bar
因为它的范围(认为它是私人的)。
好读: http : //ryanmorr.com/understanding-scope-and-context-in-javascript/