TestBed
| Since: | Angular 14(2022) |
|---|
TestBed, provided as the testing foundation for Angular, is a utility for configuring unit tests for components, services, pipes, and more. It builds a test-dedicated environment (Testing Module) in memory that closely resembles an actual Angular module, simulating real behavior including DI (dependency injection) and template compilation. It is used in combination with testing frameworks like Jasmine or Jest, and imported from @angular/core/testing.
Syntax
import { TestBed } from '@angular/core/testing';
import { ComponentFixture } from '@angular/core/testing';
// Configure the test module (call this in beforeEach of each test suite)
TestBed.configureTestingModule({
declarations: [/* Component under test (non-Standalone) */],
imports: [/* Dependent modules or Standalone components */],
providers: [/* Dependent services or alternative providers */],
});
// Generate a fixture for the component.
// Through the fixture, control the component instance, DOM, and change detection.
const fixture: ComponentFixture<MyComponent> = TestBed.createComponent(MyComponent);
// Get the component instance
const component = fixture.componentInstance;
// Manually run change detection to update the template
fixture.detectChanges();
// Retrieve a service from the DI container
const service = TestBed.inject(MyService);
Main API Overview
| API | Description |
|---|---|
TestBed.configureTestingModule(moduleDef) | Configures a test-dedicated module. Specify declarations, imports, providers, etc. |
TestBed.createComponent(component) | Generates a ComponentFixture for the specified component. Call after configureTestingModule. |
TestBed.inject(token) | Retrieves a service or token instance from the DI container. |
TestBed.overrideComponent(component, override) | Overwrites the metadata (template or providers) of an already-configured component. |
TestBed.compileComponents() | Pre-compiles components with asynchronous templates. Use with async/await. |
fixture.detectChanges() | Manually runs change detection to update the template to the latest state. |
fixture.componentInstance | Returns the instance of the component under test. Allows direct access to properties and methods. |
fixture.nativeElement | Returns the component's root DOM element. Can retrieve elements with querySelector, etc. |
fixture.debugElement | Returns Angular's debug wrapper. Enables selector search with By.css(), etc. |
fixture.whenStable() | Returns a Promise that waits until all asynchronous processing is complete. |
Sample Code
An example of writing unit tests for a counter component with TestBed. You can see the flow of DOM verification, method calls, and change detection.
// counter.component.ts
// The counter component under test.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-counter',
standalone: true,
imports: [CommonModule],
template: `
<p id="count">Count: {{ count }}</p>
<button id="btn-increment" (click)="increment()">+1</button>
<button id="btn-reset" (click)="reset()">Reset</button>
`,
})
export class CounterComponent {
count = 0;
increment(): void {
this.count++;
}
reset(): void {
this.count = 0;
}
}
// counter.component.spec.ts
// Unit tests for CounterComponent.
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { CounterComponent } from './counter.component';
describe('CounterComponent', () => {
let fixture: ComponentFixture<CounterComponent>;
let component: CounterComponent;
beforeEach(async () => {
// Configure the test module.
// CounterComponent is Standalone, so specify it in imports.
await TestBed.configureTestingModule({
imports: [CounterComponent],
}).compileComponents();
fixture = TestBed.createComponent(CounterComponent);
component = fixture.componentInstance;
// Run the first change detection to render the template.
fixture.detectChanges();
});
it('should have initial value of 0', () => {
expect(component.count).toBe(0);
});
it('should display "Count: 0" in initial state', () => {
const el: HTMLElement = fixture.nativeElement.querySelector('#count');
expect(el.textContent).toBe('Count: 0');
});
it('should increment count by 1 when +1 button is clicked', () => {
const btn = fixture.debugElement.query(By.css('#btn-increment'));
btn.triggerEventHandler('click', null);
fixture.detectChanges();
expect(component.count).toBe(1);
const el: HTMLElement = fixture.nativeElement.querySelector('#count');
expect(el.textContent).toBe('Count: 1');
});
it('should reset count to 0 after pressing +1 three times then reset', () => {
component.increment();
component.increment();
component.increment();
expect(component.count).toBe(3);
const btn = fixture.debugElement.query(By.css('#btn-reset'));
btn.triggerEventHandler('click', null);
fixture.detectChanges();
expect(component.count).toBe(0);
});
});
An example of replacing a service with a mock to test a component in isolation.
// greeting.component.spec.ts
// An example of replacing a service with a spy (mock) for testing.
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { GreetingComponent } from './greeting.component';
import { GreetingService } from './greeting.service';
describe('GreetingComponent (with mock service)', () => {
let fixture: ComponentFixture<GreetingComponent>;
let component: GreetingComponent;
// Define a mock object to use in place of GreetingService
const mockGreetingService = {
getGreeting: () => 'Hello, Test!',
};
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [GreetingComponent],
providers: [
// Replace the actual GreetingService with the mock
{ provide: GreetingService, useValue: mockGreetingService },
],
}).compileComponents();
fixture = TestBed.createComponent(GreetingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should display the greeting returned by the service', () => {
// Retrieve the mock service instance with TestBed.inject() and verify
const service = TestBed.inject(GreetingService);
expect(service.getGreeting()).toBe('Hello, Test!');
// Also verify that it is reflected in the template
const el: HTMLElement = fixture.nativeElement.querySelector('p');
expect(el.textContent).toContain('Hello, Test!');
});
});
Overview
TestBed is the utility that plays a central role in Angular testing. It builds a test-dedicated Angular module environment in memory with configureTestingModule(), and generates a ComponentFixture for the target component with createComponent(). Since the fixture allows fine-grained control of the component's instance, DOM, and change detection, you can verify component behavior without launching an actual browser.
fixture.detectChanges() manually triggers Angular's change detection. Always call it after changing properties or firing DOM events to sync the template to the latest state. There are two ways to retrieve DOM elements: fixture.nativeElement.querySelector() and fixture.debugElement.query(By.css()). When you want to accurately simulate Angular events, using the latter's triggerEventHandler() increases reliability.
To decouple from external service dependencies, replace them with mocks using useValue or useClass in providers. Since TestBed.inject() lets you retrieve DI container instances from within tests, you can also individually verify service logic. For tests involving asynchronous processing, await fixture.whenStable() waits for HTTP and timer completion.
For component testing details, see Component. For service design, see Service.
If you find any errors or copyright issues, please contact us.