cjohansen/Sinon.JS — pull request #278 by fizker (2013-04-27 00:35:49+00:00)
Title: Allow stubs to call through to other functions (original or new)

Let's say that you want to stub a function, such as `fs.readFile`, for certain inputs, but most inputs are of no interest to you.

Currently, this requires you to replace the function with your own, and perform a number of comparisons in order to decide what to do.

But stubs already have a great syntax for determining calls (`withArgs`, so as a developer writing tests, I would love to utilize this.

Towards that end, I have added the following functions to the stub interface:

- `callFake(function)`: Pipes the last call through to the given function.
- `callFakeOn(function, context)`: Pipes the last call through to the given function, and force the given context.
- `callOriginal()`: Pipes the last call through to the function that was stubbed.
- `callsFake(function)`: Pipe future calls through to the given function.
- `callsFakeOn(function, context)`: Pipe future calls through to the given function, and force the given context.
- `callsOriginal()`: Pipe all future calls through to the stubbed function. This is the default behaviour of the sinon.spy() function.

In general, we would like to combine the `withArgs()` function of stubs with the ability to either call either the original or a specific fake function, thus utilizing the quite-good comparison behind that function.

Since all calls still go through the stubs, the various assert-methods also still function as expected.

Incidentally, this also renders the `sinon.spy()` function irrelevant, as it behaves the same as `sinon.stub().callsOriginal()`, except stubs have the powerful `withArgs` function.

Scenarious where this could be useful
-------------------------------------

Replacing specific call to `fs.readFile`:

var fs = require('fs')
var sinon = require('sinon')
var readFileStub = sinon.stub(fs, 'readFile')

// We don't care about most files
readFileStub.callsOriginal()

// We do care about this specific file
readFileStub.withArgs('/path/to/interesting/file').yieldsAsync(ourFakeFile)

Overriding specific selector for `document.querySelector`:

var stub = sinon.stub(document, 'querySelector').callsOriginal()
stub.withArgs('.ourSpecificClass').returns(ourFakedElement)

Faking an ajax-response (this one might be a bit farfetched to see in practice):

var stub = sinon.stub(JSON, 'parse').callsOriginal()
stub.withArgs('fake-json').returns(ourFakeObject)

// This is responsible for parsing the JSON and parsing it on into the system
jsonFetched('fake-json')

(This potentially fixes #169, as I understood it).