Angular Unit Testing
Learn Angular Unit Testing with Jasmine, Karma, TestBed, Component Testing, Service Testing, Mocking, Spies, Async Testing, Standalone Components, and enterprise testing best practices.
Testing is an essential part of enterprise Angular development.
A well-tested application is:
- More reliable
- Easier to maintain
- Safer to refactor
- Less likely to introduce bugs
Unit Testing verifies individual units (components, services, pipes, directives, or utility functions) in isolation without depending on the entire application.
Angular provides powerful testing utilities together with Jasmine, Karma, and TestBed to simplify unit testing.
Table of Contents
- What is Unit Testing?
- Why Unit Testing?
- Angular Testing Architecture
- Jasmine
- Karma
- TestBed
- Component Testing
- Service Testing
- Mocking Dependencies
- Spies
- Async Testing
- Standalone Component Testing
- Enterprise Banking Example
- Best Practices
- Common Mistakes
- Top 10 Interview Questions
- Interview Cheat Sheet
- Summary
What is Unit Testing?
Unit Testing verifies the smallest testable part of an application independently.
Examples include:
- Component
- Service
- Pipe
- Directive
- Utility Function
Each unit is tested without relying on external systems such as databases or APIs.
Why Unit Testing?
Benefits include:
- Early bug detection
- Safe refactoring
- Better code quality
- Faster development
- Easier maintenance
- Living documentation
Angular Testing Architecture
flowchart LR
TestCase
TestCase --> TestBed
TestBed --> Component
Component --> Service
Service --> MockDependency
Angular Testing Stack
| Tool | Purpose |
|---|---|
| Jasmine | Testing framework |
| Karma | Test runner |
| TestBed | Angular testing environment |
| Spy | Mock function calls |
| Mock Objects | Fake dependencies |
| HttpTestingController | Mock HTTP requests |
Jasmine Basics
Jasmine provides the testing syntax.
Example
describe('Calculator', () => {
it('should add two numbers', () => {
expect(2 + 3).toBe(5);
});
});
Key Functions
| Function | Purpose |
|---|---|
| describe() | Test suite |
| it() | Test case |
| expect() | Assertion |
| beforeEach() | Setup |
| afterEach() | Cleanup |
Jasmine Matchers
Common matchers
expect(value).toBe(10);
expect(value).toEqual(object);
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toContain("Angular");
expect(value).toBeNull();
expect(value).toBeUndefined();
Karma
Karma is the default Angular test runner.
Responsibilities
- Executes tests
- Launches browsers
- Displays results
- Generates reports
- Watches file changes
Example
ng test
TestBed
TestBed creates an Angular testing module.
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CustomerComponent]
});
});
TestBed supports:
- Components
- Services
- Pipes
- Directives
- Dependency Injection
TestBed Architecture
flowchart LR
TestBed
TestBed --> Component
Component --> Template
Component --> Service
Service --> Mock
Component Testing
Example Component
@Component({
selector: 'app-counter',
standalone: true,
template: `
<h2>{{ count }}</h2>
`
})
export class CounterComponent {
count = 0;
}
Component Test
describe('CounterComponent', () => {
let fixture: ComponentFixture<CounterComponent>;
let component: CounterComponent;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CounterComponent]
});
fixture = TestBed.createComponent(CounterComponent);
component = fixture.componentInstance;
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
DOM Testing
fixture.detectChanges();
const element =
fixture.nativeElement.querySelector('h2');
expect(element.textContent)
.toContain('0');
Testing both the component state and the rendered DOM provides better confidence.
Service Testing
Example Service
@Injectable({
providedIn: 'root'
})
export class MathService {
add(a: number, b: number) {
return a + b;
}
}
Test
describe('MathService', () => {
let service: MathService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(MathService);
});
it('should add numbers', () => {
expect(service.add(5, 4)).toBe(9);
});
});
Mocking Dependencies
Avoid calling real APIs during unit tests.
Example
const mockCustomerService = {
getCustomers: () => []
};
Provide mock
providers: [
{
provide: CustomerService,
useValue: mockCustomerService
}
]
Jasmine Spies
Spies monitor function calls.
const service = jasmine.createSpyObj(
'CustomerService',
['loadCustomers']
);
Example
service.loadCustomers.and.returnValue([]);
expect(service.loadCustomers)
.toHaveBeenCalled();
Useful spy methods
| Method | Purpose |
|---|---|
| toHaveBeenCalled() | Verify call |
| toHaveBeenCalledTimes() | Verify count |
| toHaveBeenCalledWith() | Verify parameters |
| and.returnValue() | Mock return value |
| and.callFake() | Replace implementation |
Testing HTTP Services
Angular provides HttpTestingController.
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting()
]
});
Example
const httpMock =
TestBed.inject(HttpTestingController);
Benefits
- No real network calls
- Predictable tests
- Fast execution
Async Testing
Angular supports asynchronous testing.
Example
it('loads data', async () => {
await component.loadCustomers();
expect(component.customers.length)
.toBeGreaterThan(0);
});
Other helpers
fakeAsync()tick()waitForAsync()
Use the helper that best matches the asynchronous behavior under test.
Standalone Component Testing
Angular 17+ encourages standalone components.
Testing is simpler.
TestBed.configureTestingModule({
imports: [
CustomerComponent
]
});
No NgModule is required.
Testing Flow
flowchart TD
Test
Test --> TestBed
TestBed --> Component
Component --> Service
Service --> Mock
Mock --> Assertion
Enterprise Banking Example
Modules
- Customer Dashboard
- Accounts
- Transactions
- Payments
- Loans
Testing Strategy
| Layer | Testing |
|---|---|
| Components | UI behavior |
| Services | Business logic |
| HTTP | Mock Backend |
| Pipes | Formatting |
| Guards | Authentication |
| Interceptors | Security |
| Validators | Forms |
Test Pyramid
flowchart TD
UnitTests
IntegrationTests
EndToEndTests
EndToEndTests --> IntegrationTests
IntegrationTests --> UnitTests
Most tests should be unit tests because they are fast, isolated, and inexpensive to maintain.
Performance Best Practices
| Practice | Benefit |
|---|---|
| Mock Dependencies | Faster tests |
| Test One Behavior | Better readability |
| Avoid Shared State | Reliable execution |
| Use HttpTestingController | No real HTTP |
| Keep Tests Independent | Easy maintenance |
| Test Business Logic | Better coverage |
| Use Standalone Testing | Simpler setup |
| Run Tests in CI | Early defect detection |
Common Mistakes
Testing Multiple Behaviors Together
Each test should verify one behavior.
❌ Bad
it('should test everything', () => {
});
✅ Better
it('should create customer', () => {
});
Calling Real APIs
Never call production APIs during unit testing.
Always mock dependencies.
Forgetting detectChanges()
fixture.detectChanges();
Without it, the template may not reflect the latest component state.
Overusing TestBed
Pure functions can be tested without Angular's TestBed, resulting in faster tests.
Ignoring Negative Test Cases
Test:
- Invalid input
- Empty collections
- Null values
- Error responses
- Permission failures
Unit Testing Best Practices
| Practice | Recommendation |
|---|---|
| One Assertion Focus | One behavior per test |
| Independent Tests | Yes |
| Mock Dependencies | Always |
| Test Edge Cases | Yes |
| Avoid Production APIs | Always |
| Keep Tests Fast | Yes |
| Clear Test Names | Yes |
| Automate in CI/CD | Yes |
Advantages of Unit Testing
| Benefit | Description |
|---|---|
| Early Bug Detection | Find issues quickly |
| Safe Refactoring | Change code confidently |
| Better Design | Encourages modular code |
| Easier Maintenance | Simpler debugging |
| Faster Delivery | Prevent regressions |
| Higher Confidence | Reliable deployments |
Top 10 Unit Testing Interview Questions
1. What is Unit Testing?
Answer
Unit Testing verifies individual units of code, such as components or services, in isolation to ensure they behave as expected.
2. What is Jasmine?
Answer
Jasmine is a behavior-driven testing framework that provides functions such as describe(), it(), and expect() for writing unit tests.
3. What is Karma?
Answer
Karma is a test runner that executes Angular tests in one or more browsers and reports the results.
4. What is TestBed?
Answer
TestBed is Angular's primary testing utility for configuring dependency injection, components, services, and other Angular features in a test environment.
5. Why use mocks?
Answer
Mocks isolate the unit under test by replacing external dependencies such as APIs or databases with predictable test doubles.
6. What are Jasmine Spies?
Answer
Spies monitor and replace function calls, allowing tests to verify interactions and control return values.
7. Why use HttpTestingController?
Answer
It allows HTTP requests to be intercepted and mocked so tests remain fast and independent of real backend services.
8. How do you test asynchronous code?
Answer
Angular supports asynchronous testing through helpers such as async/await, waitForAsync(), and fakeAsync() with tick().
9. Should every Angular class use TestBed?
Answer
No. Pure TypeScript classes and utility functions can often be tested directly without TestBed.
10. What are Angular Unit Testing best practices?
Answer
- Test one behavior per test
- Mock dependencies
- Keep tests independent
- Cover edge cases
- Use descriptive test names
- Run tests in CI/CD
- Avoid real HTTP calls
Interview Cheat Sheet
| Requirement | Recommended Tool |
|---|---|
| Unit Tests | Jasmine |
| Test Runner | Karma |
| Angular Testing | TestBed |
| HTTP Testing | HttpTestingController |
| Mocking | Spy Objects |
| Component Testing | ComponentFixture |
| Async Testing | fakeAsync / waitForAsync |
| Dependency Injection | TestBed.inject() |
| Enterprise Testing | Mock Everything External |
| CI/CD | Run All Unit Tests |
Summary
Unit Testing is the foundation of a reliable Angular application. Angular provides a rich testing ecosystem with Jasmine, Karma, TestBed, and HttpTestingController, enabling developers to verify components, services, and business logic in isolation. By following best practices such as mocking external dependencies, writing focused test cases, and automating test execution in CI/CD pipelines, teams can build maintainable, high-quality enterprise applications.
Key Takeaways
- ✅ Unit Testing validates individual units in isolation.
- ✅ Jasmine is the default testing framework for Angular.
- ✅ Karma runs Angular tests in browsers.
- ✅ TestBed creates Angular testing environments.
- ✅ Mock external dependencies for reliable tests.
- ✅ Use
HttpTestingControllerfor HTTP service testing. - ✅ Standalone components simplify test setup.
- ✅ Test positive, negative, and edge-case scenarios.
- ✅ Keep tests fast, focused, and independent.
- ✅ Unit Testing is one of the most frequently asked Angular interview topics.
Next Article
➡️ 110-Component-Testing-QA.md