diff --git a/docs/release-source/release/stubs.md b/docs/release-source/release/stubs.md index 507e03308..0d6778610 100644 --- a/docs/release-source/release/stubs.md +++ b/docs/release-source/release/stubs.md @@ -95,7 +95,37 @@ Stubbing individual methods tests intent more precisely and is less susceptible If you want to create a stub object of `MyConstructor`, but don't want the constructor to be invoked, use this utility function. ```javascript -var stub = sinon.createStubInstance(MyConstructor) +var stub = sinon.createStubInstance(MyConstructor, overrides); +``` + +`overrides` is an optional map overriding created stubs, for example: + +```javascript + +var stub = sinon.createStubInstance(MyConstructor, { + foo: sinon.stub().returnsThis() +}); +``` + +is the same as: + +```javascript +var stub = sinon.createStubInstance(MyConstructor); +stub.foo.returnsThis(); +``` + +If provided value is not a stub, it will be used as the returned value: + +```javascript +var stub = sinon.createStubInstance(MyConstructor, { + foo: 3 +}); +``` +is the same as: + +```javascript +var stub = sinon.createStubInstance(MyConstructor); +stub.foo.returns(3); ``` #### `stub.withArgs(arg1[, arg2, ...]);` diff --git a/lib/sinon/stub.js b/lib/sinon/stub.js index b0ce73cce..48e131403 100644 --- a/lib/sinon/stub.js +++ b/lib/sinon/stub.js @@ -71,11 +71,28 @@ function stub(object, property) { return isStubbingNonFuncProperty ? s : wrapMethod(object, property, s); } -stub.createStubInstance = function (constructor) { +stub.createStubInstance = function (constructor, overrides) { if (typeof constructor !== "function") { throw new TypeError("The constructor should be a function."); } - return stub(Object.create(constructor.prototype)); + + var stubbedObject = stub(Object.create(constructor.prototype)); + + Object.keys(overrides || {}).forEach(function (propertyName) { + if (propertyName in stubbedObject) { + var value = overrides[propertyName]; + if (value.createStubInstance) { + stubbedObject[propertyName] = value; + } + else { + stubbedObject[propertyName].returns(value); + } + } + else { + throw new Error("Cannot stub " + propertyName + ". Property does not exist!"); + } + }); + return stubbedObject; }; /*eslint-disable no-use-before-define*/ diff --git a/test/stub-test.js b/test/stub-test.js index 0e4869213..d6250fc9d 100644 --- a/test/stub-test.js +++ b/test/stub-test.js @@ -2755,6 +2755,39 @@ describe("stub", function () { }); } }); + + it("allows providing optional overrides", function () { + var Class = function () {}; + Class.prototype.method = function () {}; + + var stub = createStubInstance(Class, { + method: createStub().returns(3) + }); + + assert.equals(3, stub.method()); + }); + + it("allows providing optional returned values", function () { + var Class = function () {}; + Class.prototype.method = function () {}; + + var stub = createStubInstance(Class, { + method: 3 + }); + + assert.equals(3, stub.method()); + }); + + it("throws an exception when trying to override non-existing property", function () { + var Class = function () {}; + Class.prototype.method = function () {}; + + assert.exception(function () { + createStubInstance(Class, { + foo: createStub().returns(3) + }); + }, {message: "Cannot stub foo. Property does not exist!"}); + }); }); describe(".callThrough", function () {