Testing in Angular (unit and integration tests)
Testing in Angular
Angular has a built-in testing framework using Jasmine (test runner) and Karma (browser runner), with TestBed for configuring test modules. Modern projects often use Jest as an alternative.
TestBed Setup
typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
describe('UserComponent', () => {
let component: UserComponent;
let fixture: ComponentFixture<UserComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UserComponent], // Standalone component
providers: [
{ provide: UserService, useValue: mockUserService }
]
}).compileComponents();
fixture = TestBed.createComponent(UserComponent);
component = fixture.componentInstance;
fixture.detectChanges(); // Trigger initial change detection
});
it('should create', () => {
expect(component).toBeTruthy();
});
});Testing Components
typescript
it('should display user name', () => {
component.user = { name: 'Alice', email: 'alice@test.com' };
fixture.detectChanges();
const nameEl = fixture.nativeElement.querySelector('h1');
expect(nameEl.textContent).toContain('Alice');
});
it('should emit event on button click', () => {
spyOn(component.delete, 'emit');
const button = fixture.nativeElement.querySelector('.delete-btn');
button.click();
expect(component.delete.emit).toHaveBeenCalledWith(component.user.id);
});Testing Services
typescript
describe('UserService', () => {
let service: UserService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
UserService,
provideHttpClient(),
provideHttpClientTesting(),
]
});
service = TestBed.inject(UserService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify(); // Ensure no outstanding requests
});
it('should fetch users', () => {
const mockUsers = [{ id: '1', name: 'Alice' }];
service.getUsers().subscribe(users => {
expect(users.length).toBe(1);
expect(users[0].name).toBe('Alice');
});
const req = httpMock.expectOne('/api/users');
expect(req.request.method).toBe('GET');
req.flush(mockUsers); // Provide mock response
});
});Mocking Dependencies
typescript
// Create a mock service
const mockUserService = {
getUsers: jasmine.createSpy().and.returnValue(of([{ name: 'Alice' }])),
deleteUser: jasmine.createSpy().and.returnValue(of(void 0)),
};
// Or use jasmine.createSpyObj
const mockAuth = jasmine.createSpyObj('AuthService', ['login', 'logout', 'isLoggedIn']);
mockAuth.isLoggedIn.and.returnValue(true);
// Provide in TestBed
providers: [
{ provide: UserService, useValue: mockUserService },
{ provide: AuthService, useValue: mockAuth },
]Testing Async Code
typescript
it('should load users on init', fakeAsync(() => {
component.ngOnInit();
tick(300); // Simulate debounce
fixture.detectChanges();
expect(component.users.length).toBe(1);
}));
it('should handle async operation', async () => {
await component.loadData();
fixture.detectChanges();
expect(component.data).toBeTruthy();
});Testing Best Practices
| Practice | Why |
|---|---|
| Mock external dependencies | Isolate the unit being tested |
Use fixture.detectChanges() | Trigger Angular's change detection |
| Test behavior, not implementation | Tests survive refactoring |
Use fakeAsync + tick | Control async timing |
httpMock.verify() in afterEach | Catch unexpected HTTP calls |
| Test edge cases | Empty data, errors, loading states |
Important:
Angular testing uses TestBed to configure a testing module with components, services, and mocks. Mock services to isolate units, use HttpTestingController for HTTP tests, and fakeAsync/tick for async operations. Always call fixture.detectChanges() after changing data. Focus on testing behavior — what the user sees and does.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.