Unit tests verify a single piece of logic in isolation, usually a service, pipe, or validator, without rendering any template. This lesson covers writing them effectively in Angular.
What Makes a Good Unit Test?
A good unit test exercises one unit of behavior (a method, a function) with a specific input, and asserts a specific, predictable output or side effect, independent of the rest of the application.
Services, pipes, and validator functions are the most natural fit for unit testing in Angular, since they're plain classes/functions with no template to render.
describe('CartService', () => {
it('calculates the total price of items in the cart', () => {
const cart = new CartService();
cart.add({ id: '1', price: 10, qty: 2 });
cart.add({ id: '2', price: 5, qty: 1 });
expect(cart.total()).toBe(25);
});
});
No TestBed, no Angular test module setup needed here, CartService is instantiated directly like any plain class.
The Arrange-Act-Assert Pattern
it('description of expected behavior', () => {
// Arrange: set up the object/data under test
const service = new MyService();
// Act: perform the behavior being tested
const result = service.doSomething(input);
// Assert: verify the outcome
expect(result).toBe(expectedValue);
});
describe() groups related tests; it() (or test()) defines an individual test case.
Arrange-Act-Assert keeps each test readable: set up, perform the action, then check the result.
expect(value).toBe(...)/toEqual(...)/toThrow(...) are common Jasmine/Jest matchers.
For services with dependencies, use TestBed to configure a testing module with mocked providers.
Unit Testing Cheatsheet
Common patterns for unit testing Angular building blocks.
fakeAsync/tick() or returning a Promise/Observable-aware test
Testing a Service With Injected Dependencies
When a service depends on another service (like HttpClient), use TestBed to configure a minimal testing module, substituting real dependencies with mocks so the test stays fast and isolated from real network calls.
describe('UserService', () => {
let service: UserService;
let httpMock: jasmine.SpyObj<HttpClient>;
beforeEach(() => {
httpMock = jasmine.createSpyObj('HttpClient', ['get']);
TestBed.configureTestingModule({
providers: [UserService, { provide: HttpClient, useValue: httpMock }],
});
service = TestBed.inject(UserService);
});
it('fetches a user by id', () => {
httpMock.get.and.returnValue(of({ id: '1', name: 'Ada' }));
service.getUser('1').subscribe(user => {
expect(user.name).toBe('Ada');
});
});
});
Testing HttpClient Calls With HttpTestingController
Rather than manually mocking HttpClient, Angular provides HttpTestingController, which intercepts real requests made through the testing module's HttpClient and lets you assert on them and control their responses directly.
Angular's fakeAsync/tick() utilities let you control simulated time in a test, useful for testing debounced logic, timers, or Promise-based flows synchronously and deterministically.
Reaching for TestBed and full Angular test module setup for a plain class/function that doesn't need it.
Testing against a real backend or real HttpClient instead of mocking it with HttpTestingController.
Writing tests that depend on execution order or shared mutable state between test cases.
Not calling httpMock.verify(), silently missing unexpected or unhandled HTTP requests in a test.
Key Takeaways
Unit tests verify one isolated piece of logic, typically a service, pipe, or validator function.
Plain classes/functions with no Angular dependencies can be tested with new directly, no TestBed required.
TestBed and HttpTestingController support testing services with real dependency injection and HTTP calls.
fakeAsync/tick() let you test timing-dependent logic (debouncing, timers) deterministically.
Pro Tip
Use HttpTestingController instead of manually mocking HttpClient with spies whenever possible, it verifies the exact URL, method, and body your service actually sends, catching subtle request-shape bugs that a loose mock would miss.
You now understand Angular unit testing. Next, learn Component Testing to verify components and their templates together.