Skip to content

Commit b49b9b3

Browse files
committed
move outline
1 parent 03aa047 commit b49b9b3

File tree

2 files changed

+171
-82
lines changed

2 files changed

+171
-82
lines changed

README.md

Lines changed: 101 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ uses a library we wrote called [quibble](https://github.com/testdouble/quibble)
9090
to monkey-patch the `require()` feature so that your subject will automatically
9191
receive your faked dependencies simply by requiring them. (If you've used
9292
something like [proxyquire](https://github.com/thlorenz/proxyquire), this is
93-
like a slightly terser form of that)
93+
like a slightly terser form of that.)
9494

9595
Here's an example of using `td.replace` in the setup of a test of a Node.js
9696
module:
@@ -128,17 +128,19 @@ in order to bypass Node's module cache and avoid test pollution
128128
* The test suite (usually in a global after-each hook) must call `td.reset()` to
129129
avoid test pollution
130130

131-
##### default exports with ES modules
131+
##### Default exports with ES modules
132132

133-
If your production code is written in ES module syntax and specifies a default
134-
export, just remember that you'll need to reference `.default` when translating
135-
to CJS syntax. That means:
133+
If your modules are written in the ES module syntax and they specify default
134+
exports, just remember that you'll need to reference `.default` when translating
135+
to CJS syntax.
136+
137+
That means instead of this:
136138

137139
```js
138140
loadsPurchases = td.replace('../src/loads-purchases')
139141
```
140142

141-
Probably needs to be written as:
143+
You probable mean to assign the fake like this:
142144

143145
```js
144146
loadsPurchases = td.replace('../src/loads-purchases').default
@@ -151,7 +153,7 @@ loadsPurchases = td.replace('../src/loads-purchases').default
151153
If you're running tests outside Node.js or otherwise injecting dependencies
152154
manually (or with a DI tool like
153155
[dependable](https://github.com/testdouble/dependable)), then you may still use
154-
`td.replace` to automatically replace things if they're addressable as
156+
`td.replace` to automatically replace things if they're referenceable as
155157
properties on an object.
156158

157159
To illustrate, suppose our subject depends on `app.signup` below:
@@ -163,7 +165,7 @@ app.signup = {
163165
}
164166
```
165167

166-
If our goal is to replace `app.signup` so during a test of `app.user.create(),
168+
If our goal is to replace `app.signup` during a test of `app.user.create()`,
167169
our test setup might look like this:
168170

169171
```js
@@ -183,16 +185,16 @@ in this case it's obviously still referenceable by the test and subject alike
183185
with `app.signup`. If we had wanted to only replace the `onCancel` function for
184186
whatever reason (though in this case, that would smell like a [partial
185187
mock](https://github.com/testdouble/contributing-tests/wiki/Partial-Mock)), we
186-
could have called `td.replace(app.signup, 'onCancel)`, instead.
188+
could have called `td.replace(app.signup, 'onCancel')`, instead.
187189

188190
Remember, calling `td.reset()` in an after-each hook (preferably globally so one
189-
doesn't have to remember in each-and-every test) so that testdouble.js can
190-
replace the original is crucial to avoiding test pollution!
191+
doesn't have to remember to do so in each-and-every test) so that testdouble.js
192+
can replace the original is crucial to avoiding hard-to-debug test pollution!
191193

192194
#### Specifying a custom replacement
193195

194196
The library's [imitation
195-
feature](https://github.com/testdouble/testdouble.js/blob/updte-readme/src/imitate/index.js)
197+
feature](https://github.com/testdouble/testdouble.js/blob/master/src/imitate/index.js)
196198
is pretty sophisticated, but it's not perfect. It's also going to be pretty slow
197199
on large, complex objects. If you'd like to specify exactly what to replace a
198200
real dependency with, you can do so in either of the above modes by providing a
@@ -216,6 +218,93 @@ signup = td.replace(app, 'signup', {
216218
})
217219
```
218220

221+
### `td.func()`, `td.object()`, and `td.constructor()` to create test doubles
222+
223+
`td.replace()`'s imitation and injection convenience is great when your
224+
project's build configuration allows for it, but in many cases you'll want or
225+
need the control to create fake things directly. Each creation function can
226+
either imitate a real thing or be specified by passing a bit of configuration.
227+
228+
Each test double creation function is very flexible and can take a variety of
229+
inputs. What gets returned generally depends on the number and type of configuration
230+
parameters passed in, so we'll highlight each supported usage separately with an
231+
example invocation:
232+
233+
#### `td.func()`
234+
235+
The `td.func()` function (also available as `td.function()`) returns a test
236+
double function and can be called in three modes:
237+
238+
* **`td.func(someRealFunction)`** - returns a test double function of the same
239+
`name`, including a deep
240+
[imitation](https://github.com/testdouble/testdouble.js/blob/master/src/imitate/index.js)
241+
of all of its custom properties
242+
* **`td.func()`** - returns an anonymous test double function that can be used
243+
for stubbing and verifying any calls against it, but whose error messages and
244+
debugging output won't have a name to trace back to it
245+
* **`td.func('some name')** - returns a test double function named 'some name',
246+
which will appear in any error messages as well as the debug info returned by
247+
passing the returned test double into `td.explain()`
248+
249+
#### `td.object()`
250+
251+
The `td.object()` function returns an object containing test double functions,
252+
and supports three types of invocations:
253+
254+
* **`td.object(realObject)`** - returns a deep
255+
[imitation](https://github.com/testdouble/testdouble.js/blob/master/src/imitate/index.js)
256+
the passed object, where each function is replaced with a test double function
257+
named for the property path (e.g. If `realObject.invoices.send()` was a
258+
function, the returned object would have a test double named
259+
`'.invoices.send'`)
260+
* **`td.object(['add', 'subtract'])`** - returns a plain JavaScript object
261+
containing two properties `add` and `subtract` that are both assigned to test
262+
double functions named `'.add'` and `'.subtract'`, respectively.
263+
* **`td.object(['a Person', {excludeMethods: ['then']})`** - when passed with no
264+
args or with a string as the first argument, returns an [ES
265+
Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy).
266+
The proxy will automatically intercept any call made to it and shunt in a test
267+
double that can be used for stubbing or verification. More details can be
268+
found in [our full docs](/docs/4-creating-test-doubles.md#objectobjectname)
269+
270+
#### `td.constructor()`
271+
272+
If your code depends on ES classes or functions intended to be called with
273+
`new`, then the `td.constructor()` function can replace those dependencies as
274+
well.
275+
276+
* **`td.constructor(RealConstructor)`** - returns a constructor whose calls can
277+
be verified and whose `prototype` functions have all been replaced with test
278+
double functions using the same
279+
[imitation](https://github.com/testdouble/testdouble.js/blob/master/src/imitate/index.js)
280+
* **`td.constructor(['select', 'save'])`** - returns a constructor with `select`
281+
and `save` properties set to test double functions named `'#select'` and
282+
`'#save'` on its `prototype` object
283+
284+
When replacing a constructor, typically the test will configure stubbing &
285+
verification by directly addressing its prototype functions.
286+
287+
To illustrate, That means in your test you might write:
288+
289+
```js
290+
const FakeConstructor = td.constructor(RealConstructor)
291+
td.when(FakeConstructor.prototype.doStuff()).thenReturn('ok')
292+
subject(FakeConstructor)
293+
```
294+
295+
So that in your production code you can:
296+
297+
```js
298+
const subject = function (SomeConstructor) {
299+
const thing = new SomeConstructor()
300+
return thing.doStuff() // returns "ok"
301+
}
302+
```
303+
304+
---
305+
# old docs:
306+
---
307+
219308
### Stubbing return values for functions
220309

221310
```js
@@ -246,73 +335,3 @@ td.verify(save(41, 'Jill'));
246335
// - called with `(41, "Jane")`.
247336
```
248337

249-
## Docs
250-
251-
All of our docs are in the [docs/](docs/) directory inside this repository and
252-
numbered for easy reading in the priority-order we anticipate people needing them.
253-
Here's a rough outline:
254-
255-
1. [Installation](docs/1-installation.md#installing-testdoublejs)
256-
1. [for Node.js](docs/1-installation.md#for-use-in-nodejs-or-browserify)
257-
2. [for browsers](docs/1-installation.md#for-use-in-browsers)
258-
3. [initial configuration](docs/1-installation.md#configuring-testdoublejs-setting-up-in-your-test-suite)
259-
2. [Purpose of testdouble.js](docs/2-howto-purpose.md#purpose)
260-
1. [in unit tests](docs/2-howto-purpose.md#test-doubles-and-unit-tests)
261-
2. [in integration tests](docs/2-howto-purpose.md#test-doubles-and-integration-tests)
262-
3. [Getting started tutorial](docs/3-getting-started.md#getting-started)
263-
4. [Creating test doubles](docs/4-creating-test-doubles.md#creating-test-doubles)
264-
1. [test double functions with `td.function()`](docs/4-creating-test-doubles.md#tdfunctionname)
265-
2. [test double objects with `td.object()`](docs/4-creating-test-doubles.md#tdobject)
266-
3. [test double constructors with `td.constructor()`](docs/4-creating-test-doubles.md#tdconstructor)
267-
5. [Stubbing responses](docs/5-stubbing-results.md#stubbing-behavior)
268-
1. [td.when() API](docs/5-stubbing-results.md#tdwhen)
269-
2. [equality argument matching](docs/5-stubbing-results.md#simple-precise-argument-stubbing)
270-
3. [one-liner stubbings](docs/5-stubbing-results.md#one-liner-stubbings)
271-
4. [stubbing sequential return values](docs/5-stubbing-results.md#stubbing-sequential-return-values)
272-
5. [argument matchers](docs/5-stubbing-results.md#loosening-stubbings-with-argument-matchers)
273-
1. [td.matchers.anything()](docs/5-stubbing-results.md#tdmatchersanything)
274-
2. [td.matchers.isA()](docs/5-stubbing-results.md#tdmatchersisa)
275-
3. [td.matchers.contains()](docs/5-stubbing-results.md#tdmatcherscontains)
276-
1. [matching strings](docs/5-stubbing-results.md#strings)
277-
2. [matching arrays](docs/5-stubbing-results.md#arrays)
278-
3. [matching objects](docs/5-stubbing-results.md#objects)
279-
4. [td.matchers.argThat()](docs/5-stubbing-results.md#tdmatchersargthat)
280-
5. [td.matchers.not()](docs/5-stubbing-results.md#tdmatchersnot)
281-
6. [Stubbing callback APIs](docs/5-stubbing-results.md#stubbing-callback-apis)
282-
7. [Stub exceptions with thenThrow](docs/5-stubbing-results.md#stub-exceptions-with-thenthrow)
283-
8. [Stub promises with thenResolve and thenReject](docs/5-stubbing-results.md#stub-promises-with-thenresolve-and-thenreject)
284-
9. [Stub side effects with thenDo](docs/5-stubbing-results.md#stub-side-effects-with-thendo)
285-
10. [Configuring stubbings](docs/5-stubbing-results.md#configuring-stubbings)
286-
1. [ignoreExtraArgs](docs/5-stubbing-results.md#ignoreextraargs)
287-
2. [times](docs/5-stubbing-results.md#times)
288-
3. [defer](docs/5-stubbing-results.md#defer)
289-
4. [delay](docs/5-stubbing-results.md#delay)
290-
6. [Verifying invocations](docs/6-verifying-invocations.md#verifying-interactions)
291-
1. [td.verify() API](docs/6-verifying-invocations.md#tdverify)
292-
2. [equality argument matching](docs/6-verifying-invocations.md#arguments)
293-
3. [argument matchers](docs/6-verifying-invocations.md#relaxing-verifications-with-argument-matchers)
294-
1. [td.matchers.anything()](docs/6-verifying-invocations.md#tdmatchersanything)
295-
2. [td.matchers.isA()](docs/6-verifying-invocations.md#tdmatchersisa)
296-
3. [td.matchers.contains()](docs/6-verifying-invocations.md#tdmatcherscontains)
297-
1. [matching strings](docs/6-verifying-invocations.md#strings)
298-
2. [matching arrays](docs/6-verifying-invocations.md#arrays)
299-
3. [matching objects](docs/6-verifying-invocations.md#objects)
300-
4. [td.matchers.argThat()](docs/6-verifying-invocations.md#tdmatchersargthat)
301-
4. [Argument captors](docs/6-verifying-invocations.md#multi-phase-assertions-with-argument-captors)
302-
5. [Configuring verifications](docs/6-verifying-invocations.md#configuring-verifications)
303-
1. [ignoreExtraArgs](docs/6-verifying-invocations.md#ignoreextraargs)
304-
2. [times](docs/6-verifying-invocations.md#times)
305-
7. [Replacing dependencies with test doubles](docs/7-replacing-dependencies.md#replacing-real-dependencies-with-test-doubles)
306-
1. [for Node.js](docs/7-replacing-dependencies.md#nodejs)
307-
2. [for Browser JS](docs/7-replacing-dependencies.md#browser)
308-
3. [td.replace() API](docs/7-replacing-dependencies.md#testdoublereplace-api)
309-
8. [Writing custom argument matchers](docs/8-custom-matchers.md#custom-argument-matchers)
310-
9. [Debugging with testdouble.js](docs/9-debugging.md#debugging-with-testdoublejs)
311-
1. [td.explain() API](docs/9-debugging.md#tdexplainsometestdouble)
312-
10. [Plugins](docs/A-plugins.md#plugins)
313-
1. [testdouble-chai](https://github.com/basecase/testdouble-chai)
314-
2. [testdouble-jasmine](https://github.com/BrianGenisio/testdouble-jasmine)
315-
11. [Frequently Asked Questions](docs/B-frequently-asked-questions.md#frequently-asked-questions)
316-
1. [Why shouldn't I call both td.when and td.verify for a single interaction with a test double?](docs/B-frequently-asked-questions.md#why-shouldnt-i-call-both-tdwhen-and-tdverify-for-a-single-interaction-with-a-test-double)
317-
12. [Configuration](docs/C-configuration.md#configuration)
318-
1. [td.config](docs/C-configuration.md#tdconfig)

docs/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Docs
2+
3+
All of our docs are in this are numbered for easy reading in the order we
4+
anticipate people will needing them. Here's an outline with links to each
5+
section:
6+
7+
1. [Installation](1-installation.md#installing-testdoublejs)
8+
1. [for Node.js](1-installation.md#for-use-in-nodejs-or-browserify)
9+
2. [for browsers](1-installation.md#for-use-in-browsers)
10+
3. [initial configuration](1-installation.md#configuring-testdoublejs-setting-up-in-your-test-suite)
11+
2. [Purpose of testdouble.js](2-howto-purpose.md#purpose)
12+
1. [in unit tests](2-howto-purpose.md#test-doubles-and-unit-tests)
13+
2. [in integration tests](2-howto-purpose.md#test-doubles-and-integration-tests)
14+
3. [Getting started tutorial](3-getting-started.md#getting-started)
15+
4. [Creating test doubles](4-creating-test-doubles.md#creating-test-doubles)
16+
1. [test double functions with `td.function()`](4-creating-test-doubles.md#tdfunctionname)
17+
2. [test double objects with `td.object()`](4-creating-test-doubles.md#tdobject)
18+
3. [test double constructors with `td.constructor()`](4-creating-test-doubles.md#tdconstructor)
19+
5. [Stubbing responses](5-stubbing-results.md#stubbing-behavior)
20+
1. [td.when() API](5-stubbing-results.md#tdwhen)
21+
2. [equality argument matching](5-stubbing-results.md#simple-precise-argument-stubbing)
22+
3. [one-liner stubbings](5-stubbing-results.md#one-liner-stubbings)
23+
4. [stubbing sequential return values](5-stubbing-results.md#stubbing-sequential-return-values)
24+
5. [argument matchers](5-stubbing-results.md#loosening-stubbings-with-argument-matchers)
25+
1. [td.matchers.anything()](5-stubbing-results.md#tdmatchersanything)
26+
2. [td.matchers.isA()](5-stubbing-results.md#tdmatchersisa)
27+
3. [td.matchers.contains()](5-stubbing-results.md#tdmatcherscontains)
28+
1. [matching strings](5-stubbing-results.md#strings)
29+
2. [matching arrays](5-stubbing-results.md#arrays)
30+
3. [matching objects](5-stubbing-results.md#objects)
31+
4. [td.matchers.argThat()](5-stubbing-results.md#tdmatchersargthat)
32+
5. [td.matchers.not()](5-stubbing-results.md#tdmatchersnot)
33+
6. [Stubbing callback APIs](5-stubbing-results.md#stubbing-callback-apis)
34+
7. [Stub exceptions with thenThrow](5-stubbing-results.md#stub-exceptions-with-thenthrow)
35+
8. [Stub promises with thenResolve and thenReject](5-stubbing-results.md#stub-promises-with-thenresolve-and-thenreject)
36+
9. [Stub side effects with thenDo](5-stubbing-results.md#stub-side-effects-with-thendo)
37+
10. [Configuring stubbings](5-stubbing-results.md#configuring-stubbings)
38+
1. [ignoreExtraArgs](5-stubbing-results.md#ignoreextraargs)
39+
2. [times](5-stubbing-results.md#times)
40+
3. [defer](5-stubbing-results.md#defer)
41+
4. [delay](5-stubbing-results.md#delay)
42+
6. [Verifying invocations](6-verifying-invocations.md#verifying-interactions)
43+
1. [td.verify() API](6-verifying-invocations.md#tdverify)
44+
2. [equality argument matching](6-verifying-invocations.md#arguments)
45+
3. [argument matchers](6-verifying-invocations.md#relaxing-verifications-with-argument-matchers)
46+
1. [td.matchers.anything()](6-verifying-invocations.md#tdmatchersanything)
47+
2. [td.matchers.isA()](6-verifying-invocations.md#tdmatchersisa)
48+
3. [td.matchers.contains()](6-verifying-invocations.md#tdmatcherscontains)
49+
1. [matching strings](6-verifying-invocations.md#strings)
50+
2. [matching arrays](6-verifying-invocations.md#arrays)
51+
3. [matching objects](6-verifying-invocations.md#objects)
52+
4. [td.matchers.argThat()](6-verifying-invocations.md#tdmatchersargthat)
53+
4. [Argument captors](6-verifying-invocations.md#multi-phase-assertions-with-argument-captors)
54+
5. [Configuring verifications](6-verifying-invocations.md#configuring-verifications)
55+
1. [ignoreExtraArgs](6-verifying-invocations.md#ignoreextraargs)
56+
2. [times](6-verifying-invocations.md#times)
57+
7. [Replacing dependencies with test doubles](7-replacing-dependencies.md#replacing-real-dependencies-with-test-doubles)
58+
1. [for Node.js](7-replacing-dependencies.md#nodejs)
59+
2. [for Browser JS](7-replacing-dependencies.md#browser)
60+
3. [td.replace() API](7-replacing-dependencies.md#testdoublereplace-api)
61+
8. [Writing custom argument matchers](8-custom-matchers.md#custom-argument-matchers)
62+
9. [Debugging with testdouble.js](9-debugging.md#debugging-with-testdoublejs)
63+
1. [td.explain() API](9-debugging.md#tdexplainsometestdouble)
64+
10. [Plugins](A-plugins.md#plugins)
65+
1. [testdouble-chai](https://github.com/basecase/testdouble-chai)
66+
2. [testdouble-jasmine](https://github.com/BrianGenisio/testdouble-jasmine)
67+
11. [Frequently Asked Questions](B-frequently-asked-questions.md#frequently-asked-questions)
68+
1. [Why shouldn't I call both td.when and td.verify for a single interaction with a test double?](B-frequently-asked-questions.md#why-shouldnt-i-call-both-tdwhen-and-tdverify-for-a-single-interaction-with-a-test-double)
69+
12. [Configuration](C-configuration.md#configuration)
70+
1. [td.config](C-configuration.md#tdconfig)

0 commit comments

Comments
 (0)