Skip to content

Commit

Permalink
2026 - Updated to support spying all methods on an object to similar …
Browse files Browse the repository at this point in the history
…to stub capabilities
  • Loading branch information
White, Ben committed May 22, 2019
1 parent ff505fc commit 181dcdd
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 0 deletions.
34 changes: 34 additions & 0 deletions docs/release-source/release/spies.md
Expand Up @@ -32,6 +32,40 @@ handles a callback, as in the following simplified example:
}
```

### Using a spy to wrap all object method

`sinon.spy(object)`

Spies all the object's methods.

Note that it's usually better practice to spy individual methods, particularly on objects that you don't understand or control all the methods for (e.g. library dependencies).

spying individual methods tests intent more precisely and is less susceptible to unexpected behavior as the object's code evolves.

The following is a slightly contrived example:

```javascript
{
sandbox: sinon.createSandbox(),

setUp: function () {
this.sandbox.spy(jQuery);
},

tearDown: function () {
this.sandbox.restore(); // Unwraps all spied methods
},

"test should inspect jQuery.getJSON's usage of jQuery.ajax": function () {
jQuery.getJSON("/some/resource");

assert(jQuery.ajax.calledOnce);
assertEquals("/some/resource", jQuery.ajax.getCall(0).args[0].url);
assertEquals("json", jQuery.ajax.getCall(0).args[0].dataType);
}
}
```


### Using a spy to wrap an existing method

Expand Down
22 changes: 22 additions & 0 deletions lib/sinon/spy-entire-object.js
@@ -0,0 +1,22 @@
"use strict";

var getPropertyDescriptor = require("./util/core/get-property-descriptor");
var walk = require("./util/core/walk");

function spyEntireObject(spy, object) {
walk(object || {}, function(prop, propOwner) {
// we don't want to spy things like toString(), valueOf(), etc. so we only spy if the object
// is not Object.prototype
if (
propOwner !== Object.prototype &&
prop !== "constructor" &&
typeof getPropertyDescriptor(propOwner, prop).value === "function"
) {
spy(object, prop);
}
});

return object;
}

module.exports = spyEntireObject;
5 changes: 5 additions & 0 deletions lib/sinon/spy.js
Expand Up @@ -9,6 +9,7 @@ var getPropertyDescriptor = require("./util/core/get-property-descriptor");
var deepEqual = require("@sinonjs/samsam").deepEqual;
var isEsModule = require("./util/core/is-es-module");
var spyCall = require("./call");
var spyEntireObject = require("./spy-entire-object");
var wrapMethod = require("./util/core/wrap-method");
var sinonFormat = require("./util/core/format");
var valueToString = require("@sinonjs/commons").valueToString;
Expand Down Expand Up @@ -36,6 +37,10 @@ function spy(object, property, types) {
return spy.create(object);
}

if (!property && typeof object === "object") {
return spyEntireObject(spy, object);
}

if (!object && !property) {
return spy.create(function() {
return;
Expand Down
19 changes: 19 additions & 0 deletions test/assert-test.js
Expand Up @@ -54,6 +54,25 @@ describe("assert", function() {
});
});

it("supports no properties", function() {
var api = {
method1: function() {
return;
},
method2: function() {
return;
}
};
sinonSpy(api);
api.method1();
api.method2();

refute.exception(function() {
sinonAssert.calledOnce(api.method1);
sinonAssert.calledOnce(api.method2);
});
});

describe(".fail", function() {
beforeEach(function() {
this.exceptionName = sinonAssert.failException;
Expand Down

0 comments on commit 181dcdd

Please sign in to comment.