1
- ### AutoMock
1
+ ### Automock
2
2
3
- #### Philosophy
4
- AutoMock is a stand-alone library. It allows complete isolation of class-dependencies
5
- during unit-testing. Automock provides on-the-fly, small DI container that contains
6
- only the class dependencies, or rather - a mock for each class dependency.
7
- By using the TypeScript reflection mechanism, AutoMock can to emit class metadata,
8
- (specifically using ` @Injectable ` decorator), and thus can perform different manipulations
9
- on the class dependencies.
3
+ Automock is a standalone library for unit testing. Using TypeScript Reflection
4
+ API (` reflect-metadata ` ) internally to produce mock objects, Automock streamlines
5
+ test development by automatically mocking class external dependencies.
10
6
11
- AutoMock cuts a lot of time when writing unit tests, and in addition, it also creates
12
- uniformity in the test writing style. It is important to say that AutoMock is intended
13
- for unit-tests only, and is not suitable for other types of tests, such as integration tests.
7
+ #### Introduction
14
8
9
+ The dependency injection container is an essential component of the Nest module system.
10
+ This container is utilized both during the testing phase and the application runtime.
15
11
16
- #### Installation
12
+ Unit tests vary from other types of tests, such as integration tests, in that they must
13
+ fully override providers/services within the DI container. External dependencies (providers)
14
+ of the so-called "unit" should be totally isolated. That is, all dependencies within
15
+ the DI container should be replaced by mock objects.
16
+
17
+ As a result, loading the modules and replacing the providers inside them is a process that
18
+ loops back on itself. Automock tackles this issue by automatically mocking all the
19
+ external dependencies/providers, resulting in total isolation of the unit/class
20
+ under test.
17
21
18
- AutoMock does not require any additional setup with Nest,
19
- simply install it and start using it.
22
+ #### Installation
20
23
21
24
``` bash
22
- $ npm i @automock/jest
25
+ $ npm i -D @automock/jest
23
26
```
24
27
25
- > info ** info** AutoMock only supports ` jest ` , soon there will be support for ` sinon `
28
+ Automock does not require any additional setup.
29
+
30
+ > info ** info** Jest is the only test framework currently supported by Automock.
31
+ Sinon will shortly be released.
26
32
27
33
#### Example
28
34
29
- Consider the following cats service, which takes three different class
30
- (constructor) parameters:
35
+ Consider the following cats service, which takes three constructor parameters:
31
36
32
37
``` ts
33
38
@@filename (cats .service )
@@ -38,94 +43,115 @@ export class CatsService {
38
43
constructor (
39
44
private logger : Logger ,
40
45
private httpService : HttpService ,
41
- private fooService : FooService ,
46
+ private catsDal : CatsDal ,
42
47
) {}
43
48
44
- public async getAllCats() {
49
+ async getAllCats() {
45
50
const cats = await this .httpService .get (' http://localhost:3000/api/cats' );
46
- this .logger .log (' Fetched all the cats! ' )
51
+ this .logger .log (' successfully fetched all cats' );
47
52
48
- this .fooService . doSomethingWithCats (cats );
53
+ this .catsDal . saveCats (cats );
49
54
}
50
55
}
51
56
```
52
57
53
- The following example shows how to create a unit-test for this service.
58
+ The service contains one public methods, ` getAllCats ` , which is the method
59
+ we use an example for the following unit test:
54
60
55
61
``` ts
56
62
@@filename (cats .service .spec )
57
- import { Spec } from ' @automock/jest' ;
63
+ import { TestBed } from ' @automock/jest' ;
58
64
import { CatsService } from ' ./cats.service' ;
59
65
60
- import Mocked = jest .Mocked ;
61
-
62
- describe (' Cats Service Spec' , () => {
63
- let catsService: CatsService ;
64
- let logger: Mocked <Logger >;
65
- let fooService: Mocked <FooService >;
66
+ describe (' Cats Service Unit Spec' , () => {
67
+ let underTest: CatsService ;
68
+ let logger: jest .Mocked <Logger >;
69
+ let httpService: jest .Mocked <HttpService >;
70
+ let catsDal: jest .Mocked <CatsDal >;
66
71
67
72
beforeAll (() => {
68
- const { unit, unitRef } = Spec .create (CatsService )
73
+ const { unit, unitRef } = TestBed .create (CatsService )
69
74
.mock (HttpService )
70
- .using ({ get : async () => Promise .resolve ([{ id: 1 , name: ' Catty' }]), })
71
75
.compile ();
72
-
73
- catsService = unit ;
76
+
77
+ underTest = unit ;
78
+
74
79
logger = unitRef .get (Logger );
75
- fooService = unitRef .get (FooService );
80
+ httpService = unitRef .get (HttpService );
81
+ catsDal = unitRef .get (CatsDal );
76
82
});
77
83
78
84
describe (' when getting all the cats' , () => {
79
- beforeAll (async () => await catsService .getAllCats ());
85
+ test (' then meet some expectations' , async () => {
86
+ httpService .mockResolvedValueOnce ([{ id: 1 , name: ' Catty' }]);
87
+ await catsService .getAllCats ();
80
88
81
- test (' then call the logger log' , () => {
82
89
expect (logger .log ).toBeCalled ();
83
- });
84
-
85
- test (' then do something with fetched data' , () => {
86
- expect (fooService .doSomethingWithCats ).toBeCalledWith ([{ id: 1 , name: ' Catty' }]);
90
+ expect (catsDal ).toBeCalledWith ([{ id: 1 , name: ' Catty' }]);
87
91
});
88
92
});
89
93
});
90
94
```
91
95
92
- > info ** Hint** The ` Mocked ` type is imported directly from ` Jest ` namespace.
96
+ > info ** info** The jest.Mocked<Source > utility type returns the Source type
97
+ > wrapped with type definitions of Jest mock function. ([ reference] ( https://jestjs.io/docs/mock-function-api/#jestmockedsource ) )
93
98
94
- #### Handling different scenarios
95
- Vivamus at pellentesque turpis. Praesent tincidunt, tellus eu ultricies faucibus,
96
- nulla velit venenatis risus, sollicitudin sollicitudin dolor lectus in dui.
97
- Integer nec lacus eu lacus sodales efficitur sed nec ligula.
99
+ \
100
+ #### About ` unit ` and ` unitRef `
101
+ Let's examine the following code:
98
102
99
- ##### Working with interfaces
100
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget faucibus felis.
101
- Integer feugiat rhoncus nibh, in elementum dolor sodales a. Pellentesque non luctus dolor,
102
- id ultrices mauris. Nulla convallis diam rhoncus mauris ultrices malesuada.
103
+ ``` typescript
104
+ const { unit, unitRef } = Spec .create (CatsService ).compile ();
105
+ ```
103
106
104
- ##### Working with ` forardRef() `
105
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget faucibus felis.
106
- Integer feugiat rhoncus nibh, in elementum dolor sodales a. Pellentesque non luctus dolor,
107
- id ultrices mauris. Nulla convallis diam rhoncus mauris ultrices malesuada.
107
+ Calling ` .compile() ` returns an object with two properties, ` unit ` , and ` unitRef ` .
108
108
109
- ##### Working with injection tokens
110
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget faucibus felis .
111
- Integer feugiat rhoncus nibh, in elementum dolor sodales a. Pellentesque non luctus dolor ,
112
- id ultrices mauris. Nulla convallis diam rhoncus mauris ultrices malesuada .
109
+ ` unitRef ` is a small container which holds the class external dependencies (that
110
+ has been replaced with mocks) .
111
+ It has one method, ` get() ` , which returns the mocked dependency, thus ,
112
+ it enables all the stubbing options from Jest .
113
113
114
- ##### Working with ` forardRef() `
114
+ > info ** info** unitRef.get() takes a string (token) or a class (dependency)
115
+
116
+ ` unit ` is the actual unit under test, it's an instance of the tested class.
117
+
118
+ #### Handling Different Scenarios
119
+ Nest offers different ways to retrieve dependencies from the DI container:
120
+ Actual class, injection tokens, and forwardRef functions. They all can be
121
+ replaced with mocks using different techniques, in the next sections you
122
+ can understand how to deal with each scenario
123
+
124
+ ##### Working with Interfaces
125
+ Consider the following ` CatsService ` which takes one param which is an instance
126
+ of the ` Logger ` interface.
127
+
128
+ ``` typescript
129
+ export interface Logger {
130
+ log(message : string ): void ;
131
+ }
132
+
133
+ export class CatsService {
134
+ constructor (private logger : Logger ) {}
135
+ }
136
+ ```
137
+
138
+ After compiling,
139
+
140
+ ##### Working with Injection Tokens (` @Inject() ` )
115
141
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam eget faucibus felis.
116
142
Integer feugiat rhoncus nibh, in elementum dolor sodales a. Pellentesque non luctus dolor,
117
143
id ultrices mauris. Nulla convallis diam rhoncus mauris ultrices malesuada.
118
144
145
+ ##### Working with ` forardRef() `
119
146
120
- #### What's the difference from Nest's built-in testing tools?
121
-
122
- Nest suggests some built in tools for creating tests, usually you need to use the ` Test ` \
123
- factory from ` @nestjs/testing ` ([ example] ( ) ) and create a new testing module. This technique \
124
- is great for creating integration/e2e tests, simply loading the whole module which includes all \
125
- the class dependencies
147
+ ``` typescript
148
+ export class HttpService {}
126
149
150
+ export class CatsService {
151
+ constructor (@Inject (forwardRef (() => HttpService )) private httpService : HttpService ) {}
152
+ }
153
+ ```
127
154
128
155
#### More Information
129
-
130
- Visit the [ AutoMock docs site] ( https://automock.dev/docs ) for more information, examples, and API documentation.
131
-
156
+ Visit [ Automock GitHub repository] ( https://github.com/omermorad/automock ) for more
157
+ information.
0 commit comments