Testing Basics
Level: Intermediate
ℹ️ What You'll Learn
- Unit testing framework (Jasmine)
- TestBed setup
- Testing components
- Testing services
- Mocking HTTP
- Running tests
Test Structure
// student.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { StudentService } from './student.service';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
describe('StudentService', () => {
let service: StudentService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [StudentService]
});
service = TestBed.inject(StudentService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});
it('should load students', () => {
const mockStudents = [
{ id: 1, name: 'Ravi' },
{ id: 2, name: 'Priya' }
];
service.getStudents().subscribe(students => {
expect(students.length).toBe(2);
expect(students[0].name).toBe('Ravi');
});
const req = httpMock.expectOne('/api/students');
expect(req.request.method).toBe('GET');
req.flush(mockStudents);
});
});
Testing Components
// student-list.component.spec.ts
describe('StudentListComponent', () => {
let component: StudentListComponent;
let fixture: ComponentFixture<StudentListComponent>;
let studentService: jasmine.SpyObj<StudentService>;
beforeEach(async () => {
const spy = jasmine.createSpyObj('StudentService', ['getStudents']);
await TestBed.configureTestingModule({
declarations: [StudentListComponent],
providers: [
{ provide: StudentService, useValue: spy }
]
}).compileComponents();
fixture = TestBed.createComponent(StudentListComponent);
component = fixture.componentInstance;
studentService = TestBed.inject(StudentService) as jasmine.SpyObj<StudentService>;
});
it('should load students on init', () => {
const mockStudents = [{ id: 1, name: 'Ravi' }];
studentService.getStudents.and.returnValue(of(mockStudents));
fixture.detectChanges();
expect(studentService.getStudents).toHaveBeenCalled();
expect(component.students).toEqual(mockStudents);
});
it('should display student names', () => {
component.students = [{ id: 1, name: 'Ravi' }];
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.textContent).toContain('Ravi');
});
});
Run Tests
# Run tests
ng test
# Run with coverage
ng test --code-coverage
# Run once (CI)
ng test --watch=false
Opens browser, runs tests automatically.
Key Testing Patterns
// Test HTTP calls
it('should create student', () => {
const student = { name: 'Ravi', email: 'ravi@school.in' };
service.createStudent(student).subscribe(result => {
expect(result.id).toBe(1);
});
const req = httpMock.expectOne('/api/students');
req.flush({ id: 1, ...student });
});
// Test error handling
it('should handle errors', () => {
let error: any;
service.getStudents().subscribe(
() => {},
err => error = err
);
const req = httpMock.expectOne('/api/students');
req.error(new ErrorEvent('Network error'));
expect(error).toBeTruthy();
});
// Test component interaction
it('should delete student', () => {
spyOn(service, 'deleteStudent').and.returnValue(of(null));
component.deleteStudent(1);
expect(service.deleteStudent).toHaveBeenCalledWith(1);
});
SMS Test Example
describe('StudentListComponent', () => {
let component: StudentListComponent;
let fixture: ComponentFixture<StudentListComponent>;
let service: jasmine.SpyObj<StudentService>;
beforeEach(async () => {
const serviceStub = jasmine.createSpyObj('StudentService', [
'getStudents',
'deleteStudent'
]);
await TestBed.configureTestingModule({
declarations: [StudentListComponent],
providers: [
{ provide: StudentService, useValue: serviceStub }
]
}).compileComponents();
fixture = TestBed.createComponent(StudentListComponent);
component = fixture.componentInstance;
service = TestBed.inject(StudentService) as jasmine.SpyObj<StudentService>;
});
it('should load and display students', () => {
const mockStudents = [
{ id: 101, name: 'Ravi Kumar', className: '10' },
{ id: 102, name: 'Priya Sharma', className: '10' }
];
service.getStudents.and.returnValue(of(mockStudents));
fixture.detectChanges();
expect(component.students.length).toBe(2);
expect(component.students[0].name).toBe('Ravi Kumar');
});
it('should delete student', () => {
service.deleteStudent.and.returnValue(of(null));
component.students = [{ id: 101, name: 'Ravi' }];
component.deleteStudent(101);
expect(service.deleteStudent).toHaveBeenCalledWith(101);
});
});
Key Takeaways
- Jasmine = testing framework
- TestBed = configure testing module
- HttpTestingModule = mock HTTP
- Spies = mock functions
- describe/it = test structure
- Run with
ng test
💡 Backend Developer Tip
Angular testing similar to NUnit/xUnit in .NET. Arrange-Act-Assert pattern applies.
⚠️ Testing Issues
- Not mocking dependencies — Real HTTP calls
- Testing implementation — Test behavior, not code
- Async not handled — fakeAsync/done() needed
- Too many assertions — One concern per test
🤖Use AI to Learn Faster
Use ChatGPT, Claude, or Copilot to go deeper on Angular Testing. Try these prompts:
"Why mock services instead of using real ones?""What's HttpTestingModule for?""How do you test component user interactions?""Quiz me on testing"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.
nexcoding.in
Have questions on your tech stack, ongoing projects, or need one-to-one training?