Skip to content

Commit

Permalink
Fake docs improvement (#2360)
Browse files Browse the repository at this point in the history
* Clarify fake api, add missing references to spy api

* Mention return value in sandbox.replace()

* Move fake changes to latest docs

* Move the sandbox change to latest docs

* Add fake runkit examples using existing spy examples

* Fix pubsub fake example

* Change runnable examples to be the same with the ones in the current documentation

* Add examples, address some review comments
  • Loading branch information
srknzl committed May 25, 2021
1 parent 399cd34 commit 40f5ca3
Show file tree
Hide file tree
Showing 14 changed files with 275 additions and 5 deletions.
@@ -0,0 +1,17 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should be able to be used instead of spies", function () {
const foo = {
bar: () => "baz",
};
// wrap existing method without changing its behaviour
const fake = sinon.replace(foo, "bar", sinon.fake(foo.bar));

assert.equals(fake(), "baz"); // behaviour is the same
assert.equals(fake.callCount, 1); // calling information is saved
});
});
17 changes: 17 additions & 0 deletions docs/release-source/release/examples/fakes-10-firstArg.test.js
@@ -0,0 +1,17 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should have working firstArg property", function () {
const f = sinon.fake();
const date1 = new Date();
const date2 = new Date();

f(date1, 1, 2);
f(date2, 1, 2);

assert.isTrue(f.firstArg === date2);
});
});
21 changes: 21 additions & 0 deletions docs/release-source/release/examples/fakes-11-lastArg.test.js
@@ -0,0 +1,21 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should have working lastArg property", function () {
const f = sinon.fake();
const date1 = new Date();
const date2 = new Date();

f(1, 2, date1);
f(1, 2, date2);

assert.isTrue(f.lastArg === date2);
// spy call methods:
assert.isTrue(f.getCall(0).lastArg === date1);
assert.isTrue(f.getCall(1).lastArg === date2);
assert.isTrue(f.lastCall.lastArg === date2);
});
});
@@ -0,0 +1,20 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should have working lastArg property", function () {
const fake = sinon.fake.returns("42");

sinon.replace(console, "log", fake);

assert.equals(console.log("apple pie"), 42);

// restores all replaced properties set by sinon methods (replace, spy, stub)
sinon.restore();

assert.equals(console.log("apple pie"), undefined);
assert.equals(fake.callCount, 1);
});
});
@@ -0,0 +1,21 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should be able to be used instead of stubs", function () {
const foo = {
bar: () => "baz",
};
// replace method with a fake one
const fake = sinon.replace(
foo,
"bar",
sinon.fake.returns("fake value")
);

assert.equals(fake(), "fake value"); // returns fake value
assert.equals(fake.callCount, 1); // saves calling information
});
});
@@ -0,0 +1,14 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should create fake without behaviour", function () {
// create a basic fake, with no behavior
const fake = sinon.fake();

assert.isUndefined(fake()); // by default returns undefined
assert.equals(fake.callCount, 1); // saves call information
});
});
@@ -0,0 +1,13 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should create fake with custom behaviour", function () {
// create a fake that returns the text "foo"
const fake = sinon.fake.returns("foo");

assert.equals(fake(), "foo");
});
});
12 changes: 12 additions & 0 deletions docs/release-source/release/examples/fakes-5-returns.test.js
@@ -0,0 +1,12 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should create a fake that 'returns' a value", function () {
const fake = sinon.fake.returns("apple pie");

assert.equals(fake(), "apple pie");
});
});
13 changes: 13 additions & 0 deletions docs/release-source/release/examples/fakes-6-throws.test.js
@@ -0,0 +1,13 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should create a fake that 'throws' an Error", function () {
const fake = sinon.fake.throws(new Error("not apple pie"));

// Expected to throw an error with message 'not apple pie'
assert.exception(fake, { name: "Error", message: "not apple pie" });
});
});
23 changes: 23 additions & 0 deletions docs/release-source/release/examples/fakes-7-yields.test.js
@@ -0,0 +1,23 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;
const fs = require("fs");

describe("FakeTest", function () {
it("should create a fake that 'yields'", function () {
const fake = sinon.fake.yields(null, "file content");
const anotherFake = sinon.fake();

sinon.replace(fs, "readFile", fake);
fs.readFile("somefile", (err, data) => {
// called with fake values given to yields as arguments
assert.isNull(err);
assert.equals(data, "file content");
// since yields is synchronous, anotherFake is not called yet
assert.isFalse(anotherFake.called);
});

anotherFake();
});
});
23 changes: 23 additions & 0 deletions docs/release-source/release/examples/fakes-8-yields-async.test.js
@@ -0,0 +1,23 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;
const fs = require("fs");

describe("FakeTest", function () {
it("should create a fake that 'yields asynchronously'", function () {
const fake = sinon.fake.yieldsAsync(null, "file content");
const anotherFake = sinon.fake();

sinon.replace(fs, "readFile", fake);
fs.readFile("somefile", (err, data) => {
// called with fake values given to yields as arguments
assert.isNull(err);
assert.equals(data, "file content");
// since yields is asynchronous, anotherFake is called first
assert.isTrue(anotherFake.called);
});

anotherFake();
});
});
20 changes: 20 additions & 0 deletions docs/release-source/release/examples/fakes-9-callback.test.js
@@ -0,0 +1,20 @@
require("@fatso83/mini-mocha").install();
const sinon = require("sinon");
const referee = require("@sinonjs/referee");
const assert = referee.assert;

describe("FakeTest", function () {
it("should have working callback property", function () {
const f = sinon.fake();
const cb1 = function () {};
const cb2 = function () {};

f(1, 2, 3, cb1);
f(1, 2, 3, cb2);

assert.isTrue(f.callback === cb2);
// spy call methods:
assert.isTrue(f.getCall(1).callback === cb2);
assert.isTrue(f.lastCall.callback === cb2);
});
});
64 changes: 60 additions & 4 deletions docs/release-source/release/fakes.md
Expand Up @@ -6,14 +6,58 @@ breadcrumb: fakes

### Introduction

`fake` is available in Sinon from v5 onwards. It allows creation of a `fake` `Function` with the ability to set a default [behavior](#fakes-with-behavior). Set the [behavior](#fakes-with-behavior) using `Functions` with the same API as those in a [`sinon.stub`][stubs]. The created `fake` `Function`, with or without behavior has the same API as a (`sinon.spy`)[spies].
`fake` is available in Sinon from v5 onwards. It allows creation of a `fake` `Function` with the ability to set a default [behavior](#fakes-with-behavior). The available [behaviors](#fakes-with-behavior) for the most part match the API of a [`sinon.stub`][stubs].

In Sinon, a `fake` is a `Function` that records arguments, return value, the value of `this` and exception thrown (if any) for all of its calls.

A fake is immutable: once created, the behavior will not change.

Unlike [`sinon.spy`][spies] and [`sinon.stub`][stubs] methods, the `sinon.fake` API knows only how to create fakes, and doesn't concern itself with plugging them into the system under test. To plug the fakes into the system under test, you can use the [`sinon.replace*`](../sandbox#sandboxreplaceobject-property-replacement) methods.

### When to use fakes?

Fakes are alternatives to the Stubs and Spies, and they can fully replace all such use cases.

They are intended to be simpler to use, and avoids many bugs by having immutable behaviour.

The created `fake` `Function`, with or without behavior has the same API as a (`sinon.spy`)[spies].

#### Using fakes instead of spies

```js
var foo = {
bar: () => {
return "baz";
},
};
// wrap existing method without changing its behaviour
var fake = sinon.replace(foo, "bar", sinon.fake(foo.bar));

fake();
// baz

fake.callCount;
// 1
```

#### Using fakes instead of stubs

```js
var foo = {
bar: () => {
return "baz";
},
};
// replace method with a fake one
var fake = sinon.replace(foo, "bar", sinon.fake.returns("fake value"));

fake();
// fake value

fake.callCount;
// 1
```

### Creating a fake

Create a `fake` `Function` with or without [behavior](#fakes-with-behavior). The created `Function` has the same API as a [`sinon.spy`][spies].
Expand Down Expand Up @@ -123,7 +167,7 @@ This is useful when complex behavior not covered by the `sinon.fake.*` methods i

### Instance properties

The instance properties are the same as a [`sinon.spy`][spies].
The instance properties are the same as those of a [`sinon.spy`][spies]. The following examples showcase just a few of the properties available to you. Refer to the [spy docs][spies] for a complete list.

#### `f.callback`

Expand All @@ -141,7 +185,7 @@ f.callback === cb2;
// true
```

The same convenience has been added to [spy calls](../spy-call):
The same convenience has been added to [spy calls](../spy-call#spycallcallback):

```js
f.getCall(1).callback === cb2;
Expand All @@ -167,6 +211,18 @@ f.firstArg === date2;
// true
```

The same convenience has been added to [spy calls](../spy-call#spycallfirstarg):

```js
f.getCall(0).firstArg === date1;
// true
f.getCall(1).firstArg === date2;
// true
//
f.lastCall.firstArg === date2;
// true
```

#### `f.lastArg`

This property is a convenient way to get a reference to the last argument passed in the last call to the fake.
Expand All @@ -183,7 +239,7 @@ f.lastArg === date2;
// true
```

The same convenience has been added to [spy calls](../spy-call):
The same convenience has been added to [spy calls](../spy-call#spycalllastarg):

```js
f.getCall(0).lastArg === date1;
Expand Down
2 changes: 1 addition & 1 deletion docs/release-source/release/sandbox.md
Expand Up @@ -183,7 +183,7 @@ _Since `sinon@2.0.0`_

#### `sandbox.replace(object, property, replacement);`

Replaces `property` on `object` with `replacement` argument. Attempts to replace an already replaced value cause an exception.
Replaces `property` on `object` with `replacement` argument. Attempts to replace an already replaced value cause an exception. Returns the `replacement`.

`replacement` can be any value, including `spies`, `stubs` and `fakes`.

Expand Down

0 comments on commit 40f5ca3

Please sign in to comment.