javascript 使用 sinon.js 使用基于真实构造函数/原型的间谍方法创建“间谍对象”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12025035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 15:06:18  来源:igfitidea点击:

Use sinon.js to create a "spy object" with spy methods based on a real constructor/prototype

javascriptnode.jsmochasinon

提问by d11wtq

I'm using sinon.js as a way to stub out dependencies in my Mocha tests. I prefer the 'spy' approach over a classic mock approach, as the introspection of the spy seems clearer and affords more flexibility than the somewhat backward-thinking with classic mock objects.

我使用 sinon.js 作为在我的 Mocha 测试中排除依赖项的一种方式。与经典的模拟方法相比,我更喜欢“间谍”方法,因为与经典模拟对象有些落后的思维相比,间谍的内省似乎更清晰,并且提供了更多的灵活性。

That said, I wonder if I'm using it incorrectly when it comes to creating test spies for whole objects. Let's say I have a test dependency that has 4 methods on it and I want to stub each of those methods and make assertions on one or two of them. Currently I'm doing this:

也就是说,我想知道在为整个对象创建测试间谍时我是否错误地使用了它。假设我有一个测试依赖项,它有 4 个方法,我想存根这些方法中的每一个并对其中的一两个方法进行断言。目前我正在这样做:

var spyObj = {
  aMethod: sinon.spy(),
  otherMethod: sinon.spy(),
  whatever: sinon.spy()
};

Then I just ask things like spyObj.aMethod.calledWith(a, b, c).

然后我只问诸如spyObj.aMethod.calledWith(a, b, c).

Is there a better way to mock out an entire class than repeating the names of the methods in the test suite itself? It looks like sinon.stub() tries to iterate over all the member of a given object, but that doesn't seem to work as a way to get all methods for most objects in more modern JS runtimes, like V8, unless the object is actually something enumerable. It also tries to monkey patch the actual object, rather than returning an equivalent one, which is somewhat undesirable. I just need an object that conforms to an interface, but behaves like a null object, unless I tell it otherwise.

有没有比在测试套件本身中重复方法名称更好的模拟整个类的方法?看起来 sinon.stub() 试图遍历给定对象的所有成员,但这似乎不能作为在更现代的 JS 运行时(如 V8)中获取大多数对象的所有方法的方法,除非对象实际上是可数的东西。它还尝试对实际对象进行猴子修补,而不是返回等效的对象,这在某种程度上是不可取的。我只需要一个符合接口的对象,但行为就像一个空对象,除非我另有说明。

It would be good to be able to do something like:

能够执行以下操作会很好:

var spyObject = sinon.spy(MyClass.prototype);

How does one find all methods of a constructor/prototype in Node.js, in order to make a wrapper like the above?

如何在 Node.js 中找到构造函数/原型的所有方法,以便制作像上面这样的包装器?

This is more about stubbing out logic, than testing invocations on lots of methods (which I try to limit to one, or at a push two). For example, things that might do unwanted I/O, or require additional complex fixtures if executed.

这更多地是关于剔除逻辑,而不是测试对许多方法的调用(我试图限制为一种,或者推两种)。例如,可能会执行不需要的 I/O,或者在执行时需要额外的复杂装置的事情。

回答by tfischbach

Starting with Sinon 1.6.0 you can do:

从 Sinon 1.6.0 开始,您可以执行以下操作:

var stub = sinon.createStubInstance(MyClass)

See documentation for sinon.stubin Stub API sectionor the source.

为见文档sinon.stub中的存根API部分

回答by d11wtq

I found a way to do this:

我找到了一种方法来做到这一点:

/** Accept a prototype and return a full stub object */
function stub(obj, target) {
  var cls = (typeof obj == 'function') ? obj.prototype : obj;
  target = target || {};

  Object.getOwnPropertyNames(cls).filter(function(p){
    return typeof cls[p] == 'function';
  }).forEach(function(p) { target[p] = sinon.stub() });

  return cls.__proto__ ? stub(cls.__proto__, target) : target;
};

Use it like this:

像这样使用它:

var response = stub(http.ServerResponse);
response.getHeader.withArgs('X-Foo').returns('bob');
response.getHeader.withArgs('X-Bar').returns('barry');

console.log(response.getHeader('X-Foo')); // bob
console.log(response.getHeader('X-Bar')); // barry