如何存根require()/期望对“root”的调用模块的功能? [英] How to stub require() / expect calls to the "root" function of a module?

查看:121
本文介绍了如何存根require()/期望对“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();
  });
});

这完全正常。像这样的东西使它变绿:

This is working perfectly fine. Something like this makes it green:

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

这是我要用此规范测试的代码:

This is the code I'd like to test with this spec:

something.act = function() { require('my_module')(); };

在过去的几个月里,这已经让我失望了好几次。一个理论解决方案是替换require()并返回使用createSpy()创建的间谍。但是require()是一个不可阻挡的野兽:它是每个源文件/模块中函数的不同副本。在规范中对它进行存根不会取代testee源文件中的真实require()函数。

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.

有什么想法吗?

推荐答案

看起来我找到了一个可接受的解决方案。

It looks like I found an acceptable solution.

规范助手:

var moduleSpies = {};
var originalJsLoader = require.extensions['.js'];

spyOnModule = function spyOnModule(module) {
  var path          = require.resolve(module);
  var spy           = createSpy("spy on module \"" + module + "\"");
  moduleSpies[path] = spy;
  delete require.cache[path];
  return spy;
};

require.extensions['.js'] = function (obj, path) {
  if (moduleSpies[path])
    obj.exports = moduleSpies[path];
  else
    return originalJsLoader(obj, path);
}

afterEach(function() {
  for (var path in moduleSpies) {
    delete moduleSpies[path];
  }
});

规格:

describe("something.act()", function() {
  it("calls the 'root' function of my module", function() {
    var mod = spyOnModule('my_module');
    something.act();
    expect(mod).toHaveBeenCalled(); // mod is a spy
  });
});

这并不完美,但工作做得很好。它甚至没有弄乱 testee 源代码,这对我来说是一种标准。

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.

这篇关于如何存根require()/期望对“root”的调用模块的功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆