如何存根 require() / Expect 对“root”的调用模块的功能?
考虑以下茉莉花规范:
describe("something.act()", function() {
it("calls some function of my module", function() {
var mod = require('my_module');
spyOn(mod, "someFunction");
something.act();
expect(mod.someFunction).toHaveBeenCalled();
});
});
这工作得很好。像这样的东西使它变得绿色:
something.act = function() { require('my_module').someFunction(); };
现在看看这个:
describe("something.act()", function() {
it("calls the 'root' function of my module", function() {
var mod = require('my_module');
spyOn(mod); // jasmine needs a property name
// pointing to a function as param #2
// therefore, this call is not correct.
something.act();
expect(mod).toHaveBeenCalled(); // mod should be a spy
});
});
这是我想用这个规范测试的代码:
something.act = function() { require('my_module')(); };
在过去的几个月里,这让我陷入了困境。一种理论上的解决方案是替换 require() 并返回使用 createSpy() 创建的间谍。但是 require() 是一个不可阻挡的野兽:它是每个源文件/模块中函数的不同“副本”。在规范中存根它不会替换“testee”源文件中真正的 require() 函数。
另一种方法是在加载路径中添加一些假模块,但对我来说它看起来太复杂了。
有什么想法吗?
Consider the following jasmine spec:
describe("something.act()", function() {
it("calls some function of my module", function() {
var mod = require('my_module');
spyOn(mod, "someFunction");
something.act();
expect(mod.someFunction).toHaveBeenCalled();
});
});
This is working perfectly fine. Something like this makes it green:
something.act = function() { require('my_module').someFunction(); };
Now have a look at this one:
describe("something.act()", function() {
it("calls the 'root' function of my module", function() {
var mod = require('my_module');
spyOn(mod); // jasmine needs a property name
// pointing to a function as param #2
// therefore, this call is not correct.
something.act();
expect(mod).toHaveBeenCalled(); // mod should be a spy
});
});
This is the code I'd like to test with this spec:
something.act = function() { require('my_module')(); };
This has bogged me down several times in the last few months. One theoretical solution would be to replace require() and return a spy created with createSpy(). BUT require() is an unstoppable beast: it is a different "copy" of the function in each and every source file/module. Stubbing it in the spec won't replace the real require() function in the "testee" source file.
An alternative is to add some fake modules to the load path, but it looks too complicated to me.
Any idea?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
rewire 对此非常棒
rewire is awesome for this
看起来我找到了一个可以接受的解决方案。
规范助手:
规范:
这并不完美,但做得很好。它甚至不会与测试者源代码混淆,这对我来说是一种标准。
It looks like I found an acceptable solution.
The spec helper:
The spec:
This is not perfect but does the job quite well. It does not even mess with the testee source code, which is kind of a criterion for me.
我今天需要这样做并发现了这篇文章。我的解决方案如下:
在规范助手中:
在规范中:
I needed to do this today and came across this post. My solution follows:
In a spec helper:
In a spec:
这非常有帮助,但它不支持通过
.andCallThrough()
进行调用。不过我能够适应它,所以我想我会分享:
This was very helpful, but it doesn't support calling through via
.andCallThrough()
.I was able to adapt it though, so I thought I'd share:
您可以使用gently模块(https://github.com/felixge/node-gently)。示例中提到了劫持 require,并且肮脏的 NPM 模块积极使用它,所以我认为它是有效的。
You can use gently module (https://github.com/felixge/node-gently). Hijacking require is mentioned in examples, and dirty NPM module actively uses it, so I suppose it works.
还有另一种方法。您可以在需要时不使用
var
将模块放入全局范围:您也可以将模块包装在另一个模块中:
然后显然确保无论
someFunctionThatShouldCallTheModule
是,您需要包装器而不是真正的模块。There is another approach. You can put the module in the global scope by not using
var
when requiring it:You could also wrap the module in another module:
And then obviously make sure that wherever
someFunctionThatShouldCallTheModule
is, you're requiring the wrapper rather than the real module.