In #37957, parts of the testing guide were broken out into separate guides. As part of that work, the `<live-example>` tags were also copied to the new guides. These `<live-example>` tags did not specify the targeted example project via the `name` attribute, thus they were implicitly targeting the example with the same name as the guide they were in. See the [Docs style guide][1] for more info. However, there is only one example project (`testing/`) and all `<live-example>` tags were supposed to target that. This worked fine on the `testing.md` guide, but it broke on other guides (which tried to target non-existing example projects based on their names). This commit fixes it by explicitly specifying which example is targeted by the `<live-example>` tags. It also removes the `embedded-style` attribute that has no effect. [1]: https://angular.io/guide/docs-style-guide#live-examples Fixes #38036 PR Close #38038
		
			
				
	
	
		
			200 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Testing services
 | |
| 
 | |
| 
 | |
| To check that your services are working as you intend, you can write tests specifically for them.
 | |
| 
 | |
| <div class="alert is-helpful">
 | |
| 
 | |
|   For the sample app that the testing guides describe, see the <live-example name="testing" embedded-style noDownload>sample app</live-example>.
 | |
| 
 | |
|   For the tests features in the testing guides, see <live-example name="testing" stackblitz="specs" noDownload>tests</live-example>.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| 
 | |
| Services are often the easiest files to unit test.
 | |
| Here are some synchronous and asynchronous unit tests of the `ValueService`
 | |
| written without assistance from Angular testing utilities.
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.spec.ts" region="ValueService" header="app/demo/demo.spec.ts"></code-example>
 | |
| 
 | |
| {@a services-with-dependencies}
 | |
| 
 | |
| ## Services with dependencies
 | |
| 
 | |
| Services often depend on other services that Angular injects into the constructor.
 | |
| In many cases, it's easy to create and _inject_ these dependencies by hand while
 | |
| calling the service's constructor.
 | |
| 
 | |
| The `MasterService` is a simple example:
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.ts" region="MasterService" header="app/demo/demo.ts"></code-example>
 | |
| 
 | |
| `MasterService` delegates its only method, `getValue`, to the injected `ValueService`.
 | |
| 
 | |
| Here are several ways to test it.
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.spec.ts" region="MasterService" header="app/demo/demo.spec.ts"></code-example>
 | |
| 
 | |
| The first test creates a `ValueService` with `new` and passes it to the `MasterService` constructor.
 | |
| 
 | |
| However, injecting the real service rarely works well as most dependent services are difficult to create and control.
 | |
| 
 | |
| Instead you can mock the dependency, use a dummy value, or create a
 | |
| [spy](https://jasmine.github.io/2.0/introduction.html#section-Spies)
 | |
| on the pertinent service method.
 | |
| 
 | |
| <div class="alert is-helpful">
 | |
| 
 | |
| Prefer spies as they are usually the easiest way to mock services.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| These standard testing techniques are great for unit testing services in isolation.
 | |
| 
 | |
| However, you almost always inject services into application classes using Angular
 | |
| dependency injection and you should have tests that reflect that usage pattern.
 | |
| Angular testing utilities make it easy to investigate how injected services behave.
 | |
| 
 | |
| ## Testing services with the _TestBed_
 | |
| 
 | |
| Your app relies on Angular [dependency injection (DI)](guide/dependency-injection)
 | |
| to create services.
 | |
| When a service has a dependent service, DI finds or creates that dependent service.
 | |
| And if that dependent service has its own dependencies, DI finds-or-creates them as well.
 | |
| 
 | |
| As service _consumer_, you don't worry about any of this.
 | |
| You don't worry about the order of constructor arguments or how they're created.
 | |
| 
 | |
| As a service _tester_, you must at least think about the first level of service dependencies
 | |
| but you _can_ let Angular DI do the service creation and deal with constructor argument order
 | |
| when you use the `TestBed` testing utility to provide and create services.
 | |
| 
 | |
| {@a testbed}
 | |
| 
 | |
| ## Angular _TestBed_
 | |
| 
 | |
| The `TestBed` is the most important of the Angular testing utilities.
 | |
| The `TestBed` creates a dynamically-constructed Angular _test_ module that emulates
 | |
| an Angular [@NgModule](guide/ngmodules).
 | |
| 
 | |
| The `TestBed.configureTestingModule()` method takes a metadata object that can have most of the properties of an [@NgModule](guide/ngmodules).
 | |
| 
 | |
| To test a service, you set the `providers` metadata property with an
 | |
| array of the services that you'll test or mock.
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="value-service-before-each" header="app/demo/demo.testbed.spec.ts (provide ValueService in beforeEach)"></code-example>
 | |
| 
 | |
| Then inject it inside a test by calling `TestBed.inject()` with the service class as the argument.
 | |
| 
 | |
| <div class="alert is-helpful">
 | |
| 
 | |
| **Note:** `TestBed.get()` was deprecated as of Angular version 9.
 | |
| To help minimize breaking changes, Angular introduces a new function called `TestBed.inject()`, which you should use instead.
 | |
| For information on the removal of `TestBed.get()`,
 | |
| see its entry in the [Deprecations index](guide/deprecations#index).
 | |
| 
 | |
| </div>
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="value-service-inject-it"></code-example>
 | |
| 
 | |
| Or inside the `beforeEach()` if you prefer to inject the service as part of your setup.
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="value-service-inject-before-each"> </code-example>
 | |
| 
 | |
| When testing a service with a dependency, provide the mock in the `providers` array.
 | |
| 
 | |
| In the following example, the mock is a spy object.
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="master-service-before-each"></code-example>
 | |
| 
 | |
| The test consumes that spy in the same way it did earlier.
 | |
| 
 | |
| <code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="master-service-it">
 | |
| </code-example>
 | |
| 
 | |
| {@a no-before-each}
 | |
| 
 | |
| ## Testing without _beforeEach()_
 | |
| 
 | |
| Most test suites in this guide call `beforeEach()` to set the preconditions for each `it()` test
 | |
| and rely on the `TestBed` to create classes and inject services.
 | |
| 
 | |
| There's another school of testing that never calls `beforeEach()` and prefers to create classes explicitly rather than use the `TestBed`.
 | |
| 
 | |
| Here's how you might rewrite one of the `MasterService` tests in that style.
 | |
| 
 | |
| Begin by putting re-usable, preparatory code in a _setup_ function instead of `beforeEach()`.
 | |
| 
 | |
| <code-example
 | |
|   path="testing/src/app/demo/demo.spec.ts"
 | |
|   region="no-before-each-setup"
 | |
|   header="app/demo/demo.spec.ts (setup)"></code-example>
 | |
| 
 | |
| The `setup()` function returns an object literal
 | |
| with the variables, such as `masterService`, that a test might reference.
 | |
| You don't define _semi-global_ variables (e.g., `let masterService: MasterService`)
 | |
| in the body of the `describe()`.
 | |
| 
 | |
| Then each test invokes `setup()` in its first line, before continuing
 | |
| with steps that manipulate the test subject and assert expectations.
 | |
| 
 | |
| <code-example
 | |
|   path="testing/src/app/demo/demo.spec.ts"
 | |
|   region="no-before-each-test"></code-example>
 | |
| 
 | |
| Notice how the test uses
 | |
| [_destructuring assignment_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)
 | |
| to extract the setup variables that it needs.
 | |
| 
 | |
| <code-example
 | |
|   path="testing/src/app/demo/demo.spec.ts"
 | |
|   region="no-before-each-setup-call">
 | |
| </code-example>
 | |
| 
 | |
| Many developers feel this approach is cleaner and more explicit than the
 | |
| traditional `beforeEach()` style.
 | |
| 
 | |
| Although this testing guide follows the traditional style and
 | |
| the default [CLI schematics](https://github.com/angular/angular-cli)
 | |
| generate test files with `beforeEach()` and `TestBed`,
 | |
| feel free to adopt _this alternative approach_ in your own projects.
 | |
| 
 | |
| ## Testing HTTP services
 | |
| 
 | |
| Data services that make HTTP calls to remote servers typically inject and delegate
 | |
| to the Angular [`HttpClient`](guide/http) service for XHR calls.
 | |
| 
 | |
| You can test a data service with an injected `HttpClient` spy as you would
 | |
| test any service with a dependency.
 | |
| <code-example
 | |
|   path="testing/src/app/model/hero.service.spec.ts"
 | |
|   region="test-with-spies"
 | |
|   header="app/model/hero.service.spec.ts (tests with spies)">
 | |
| </code-example>
 | |
| 
 | |
| <div class="alert is-important">
 | |
| 
 | |
| The `HeroService` methods return `Observables`. You must
 | |
| _subscribe_ to an observable to (a) cause it to execute and (b)
 | |
| assert that the method succeeds or fails.
 | |
| 
 | |
| The `subscribe()` method takes a success (`next`) and fail (`error`) callback.
 | |
| Make sure you provide _both_ callbacks so that you capture errors.
 | |
| Neglecting to do so produces an asynchronous uncaught observable error that
 | |
| the test runner will likely attribute to a completely different test.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| ## _HttpClientTestingModule_
 | |
| 
 | |
| Extended interactions between a data service and the `HttpClient` can be complex
 | |
| and difficult to mock with spies.
 | |
| 
 | |
| The `HttpClientTestingModule` can make these testing scenarios more manageable.
 | |
| 
 | |
| While the _code sample_ accompanying this guide demonstrates `HttpClientTestingModule`,
 | |
| this page defers to the [Http guide](guide/http#testing-http-requests),
 | |
| which covers testing with the `HttpClientTestingModule` in detail.
 | |
| 
 |