@@ -90,7 +90,7 @@ uses a library we wrote called [quibble](https://github.com/testdouble/quibble)
90
90
to monkey-patch the ` require() ` feature so that your subject will automatically
91
91
receive your faked dependencies simply by requiring them. (If you've used
92
92
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. )
94
94
95
95
Here's an example of using ` td.replace ` in the setup of a test of a Node.js
96
96
module:
@@ -128,17 +128,19 @@ in order to bypass Node's module cache and avoid test pollution
128
128
* The test suite (usually in a global after-each hook) must call ` td.reset() ` to
129
129
avoid test pollution
130
130
131
- ##### default exports with ES modules
131
+ ##### Default exports with ES modules
132
132
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:
136
138
137
139
``` js
138
140
loadsPurchases = td .replace (' ../src/loads-purchases' )
139
141
```
140
142
141
- Probably needs to be written as :
143
+ You probable mean to assign the fake like this :
142
144
143
145
``` js
144
146
loadsPurchases = td .replace (' ../src/loads-purchases' ).default
@@ -151,7 +153,7 @@ loadsPurchases = td.replace('../src/loads-purchases').default
151
153
If you're running tests outside Node.js or otherwise injecting dependencies
152
154
manually (or with a DI tool like
153
155
[ 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
155
157
properties on an object.
156
158
157
159
To illustrate, suppose our subject depends on ` app.signup ` below:
@@ -163,7 +165,7 @@ app.signup = {
163
165
}
164
166
```
165
167
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() ` ,
167
169
our test setup might look like this:
168
170
169
171
``` js
@@ -183,16 +185,16 @@ in this case it's obviously still referenceable by the test and subject alike
183
185
with ` app.signup ` . If we had wanted to only replace the ` onCancel ` function for
184
186
whatever reason (though in this case, that would smell like a [ partial
185
187
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.
187
189
188
190
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!
191
193
192
194
#### Specifying a custom replacement
193
195
194
196
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 )
196
198
is pretty sophisticated, but it's not perfect. It's also going to be pretty slow
197
199
on large, complex objects. If you'd like to specify exactly what to replace a
198
200
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', {
216
218
})
217
219
```
218
220
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
+
219
308
### Stubbing return values for functions
220
309
221
310
``` js
@@ -246,73 +335,3 @@ td.verify(save(41, 'Jill'));
246
335
// - called with `(41, "Jane")`.
247
336
```
248
337
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 )
0 commit comments