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

  1. What is Unit Testing?
  2. Why Unit Testing?
  3. Angular Testing Architecture
  4. Jasmine
  5. Karma
  6. TestBed
  7. Component Testing
  8. Service Testing
  9. Mocking Dependencies
  10. Spies
  11. Async Testing
  12. Standalone Component Testing
  13. Enterprise Banking Example
  14. Best Practices
  15. Common Mistakes
  16. Top 10 Interview Questions
  17. Interview Cheat Sheet
  18. 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 HttpTestingController for 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