Introduction
Unit testing and Test-Driven Development (TDD) are essential practices for building robust and reliable Angular applications. Unit tests verify the correctness of individual units of code, such as components, services, and directives, in isolation. TDD is an approach that emphasizes writing tests before writing the actual code, ensuring that the code meets the desired requirements. This blog will explore unit testing and TDD in Angular, along with practical example
If you want to learn about the testing features of angular, you can refer here.
Why Unit Testing and TDD in Angular?
Unit testing and TDD offer several benefits when developing Angular applications:
- Code Reliability: Unit tests help detect bugs and errors early in the development process, ensuring that code behaves as expected and minimizing potential issues.
- Refactoring Safety: Having comprehensive unit tests provides confidence when refactoring code, as tests serve as a safety net to catch any regressions.
- Faster Debugging: When a test fails, it allows developers to pinpoint the exact issue quickly, simplifying debugging and reducing the time spent on bug fixing.
- Continuous Integration: Automated unit tests are a crucial part of a continuous integration process, enabling continuous delivery and faster feedback cycles.
Setting Up Unit Testing in Angular
Angular comes with a built-in testing framework based on Karma and Jasmine, making it easy to set up and execute unit tests.
Step 1: Create a New Angular Project
If you haven’t created an Angular project yet, use Angular CLI to create a new project:
ng new angular-testing-example
cd angular-testing-example
Step 2: Writing a Simple Unit Test
Let’s write a simple unit test for a service that performs basic arithmetic operations.
Step 2.1: Generate the Service
Create a new service called calculator
using Angular CLI:
ng generate service calculator
Step 2.2: Implement the Service
Open the calculator.service.ts
file and implement the arithmetic operations:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class CalculatorService {
add(a: number, b: number): number {
return a + b;
}
subtract(a: number, b: number): number {
return a - b;
}
multiply(a: number, b: number): number {
return a * b;
}
divide(a: number, b: number): number {
if (b === 0) {
throw new Error('Division by zero is not allowed.');
}
return a / b;
}
}
Step 2.3: Write the Unit Test
Create a new file calculator.service.spec.ts
in the same directory as calculator.service.ts
. This is where the unit tests for the CalculatorService
will reside.
import { TestBed } from '@angular/core/testing';
import { CalculatorService } from './calculator.service';
describe('CalculatorService', () => {
let service: CalculatorService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CalculatorService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should add two numbers', () => {
expect(service.add(2, 3)).toEqual(5);
});
it('should subtract two numbers', () => {
expect(service.subtract(5, 3)).toEqual(2);
});
it('should multiply two numbers', () => {
expect(service.multiply(2, 3)).toEqual(6);
});
it('should divide two numbers', () => {
expect(service.divide(6, 3)).toEqual(2);
});
it('should throw an error when dividing by zero', () => {
expect(() => service.divide(5, 0)).toThrowError('Division by zero is not allowed.');
});
});
Step 2.4: Run the Unit Tests
Execute the unit tests using the Angular CLI:
ng test
The tests should pass, confirming that the CalculatorService
is functioning as expected.
Test-Driven Development (TDD) in Angular
Test-Driven Development (TDD) is an approach where you write tests before writing the actual code. The TDD process follows three steps:
- Write a Test: Start by writing a test that defines the behavior or functionality you want to implement.
- Run the Test: Run the test and observe it failing, as the functionality has not been implemented yet.
- Write the Code: Write the code necessary to make the test pass.
Example: TDD for a Simple Angular Component
Let’s follow the TDD approach to create a simple Angular component that displays a message.
Step 1: Write a Test
Create a new file message.component.spec.ts
in the same directory as message.component.ts
(if using Angular CLI, it should already create the test file when you generate the component).
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MessageComponent } from './message.component';
describe('MessageComponent', () => {
let component: MessageComponent;
let fixture: ComponentFixture<MessageComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [MessageComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(MessageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should display the correct message', () => {
const message = 'Hello, World!';
component.message = message;
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('p').textContent).toContain(message);
});
});
Step 2: Run the Test
Running the test at this stage should result in a failure since the component has not been implemented yet.
Step 3: Write the Code
Now, let’s implement the MessageComponent
.
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-message',
template: '<p>{{ message }}</p>',
})
export class MessageComponent {
@Input() message = '';
}
Step 4: Run the Test Again
Running the test after implementing the component should now pass successfully.
Conclusion
Unit testing and Test-Driven Development (TDD) are crucial practices for developing reliable and maintainable Angular applications. In this blog, we explored how to set up unit testing in Angular using Jasmine and Karma. We also discussed the TDD approach, which involves writing tests before writing the actual code.
By writing comprehensive unit tests and following the TDD approach, you can ensure that your Angular application behaves as expected and is less prone to errors and regressions. Adopting unit testing and TDD as part of your development workflow can greatly improve the quality and reliability of your Angular applications. Happy testing and coding in Angular!
Finally, for more such posts, please follow our LinkedIn page- FrontEnd Competency.