2. Angular

Angular는 Google에서 개발한 TypeScript 기반의 프론트엔드 웹 애플리케이션 개발 프레임워크입니다. Angular는 컴포넌트 기반 아키텍처, 강력한 템플릿 엔진, 데이터 바인딩, 의존성 주입 등의 기능을 제공하여 확장 가능하고 유지보수가 용이한 애플리케이션을 개발할 수 있도록 도와줍니다.

1. TypeScript란?

TypeScript는 추가 기능을 제공하고 오류를 조기에 포착하여 개발자가 더 나은 JavaScript 코드를 작성할 수 있도록 도와주는 언어입니다 TypeScript가 이러한 추가 기능을 추가하더라도 여전히 일반 JavaScript에서 작동합니다. TypeScript 코드를 작성한 다음 모든 JavaScript 환경에서 실행할 수 있는 JavaScript 코드로 "트랜스파일"할 수 있습니다.

2. 템플릿 문법

Angular 템플릿 구문은 컴포넌트와 상호 작용하고, 데이터 바인딩을 수행하고, 이벤트를 처리하기 위해 Angular 템플릿에서 사용되는 특수 구문입니다. 일반 HTML의 기능을 확장하여 동적 렌더링 및 데이터 조작을 가능하게 합니다. 다음은 Angular 템플릿 구문의 몇 가지 주요 기능입니다.

1) 보간({{ }})

  • 보간을 사용하면 템플릿 내에서 구성 요소 속성을 표시할 수 있습니다.

  • 이중 중괄호 {{ }}를 사용하여 평가되고 렌더링된 출력에 표시될 표현식을 포함할 수 있습니다.

  • 예: <h1>{{ 제목 }}</h1>

2) 속성 바인딩([])

  • 속성 바인딩을 사용하면 구성 요소 속성을 HTML 요소 특성, 속성 또는 지시문에 바인딩할 수 있습니다.

  • 대괄호 []를 사용하여 속성을 식이나 값에 바인딩할 수 있습니다.

  • 예: <입력 [값]="이름">

3) 이벤트 바인딩(())

  • 이벤트 바인딩을 사용하면 사용자 이벤트(예: 버튼 클릭, 입력 변경)에 응답하고 구성 요소 메서드를 트리거할 수 있습니다.

  • 괄호 ()를 사용하여 이벤트를 구성 요소 메서드에 바인딩할 수 있습니다.

  • 예: <button (click)="submit()">제출</button>

4) 양방향 바인딩([()])

  • 양방향 바인딩은 속성 바인딩과 이벤트 바인딩을 결합하여 구성 요소와 템플릿 간의 데이터 동기화를 허용합니다.

  • 괄호 [(ngModel)]과 함께 대괄호를 사용하여 양방향 바인딩을 구현할 수 있습니다.

  • 양방향 바인딩을 사용하려면 Angular 모듈에서 'FormsModule'을 가져와야 합니다.

  • 예: <입력 [(ngModel)]="이름">

5) 지시문(*)

  • Angular의 지시문은 추가 기능 또는 동작으로 HTML을 확장합니다.

  • 별표 *는 DOM 구조를 조작하는 구조 지시문을 나타내는 데 사용됩니다.

  • 예를 들어 *ngFor는 컬렉션을 반복하고 여러 요소를 생성하는 데 사용되는 구조적 지시문입니다.

6) 템플릿 참조 변수(#)

  • 템플릿 참조 변수를 사용하면 템플릿 내에서 HTML 요소 또는 Angular 구성 요소를 참조할 수 있습니다.

  • 해시 기호 #를 사용하여 참조 변수를 정의할 수 있습니다.

  • 예: <input #myInput>

7) 조건부 렌더링(*ngIf, *ngSwitch, *ngFor)

  • Angular는 조건부 렌더링 및 반복을 위한 몇 가지 구조적 지시문을 제공합니다.

  • *ngIf는 조건에 따라 DOM에서 요소를 조건부로 렌더링하거나 제거하는 데 사용됩니다.

  • *ngSwitch는 값에 따라 여러 요소 중 하나를 조건부로 렌더링하는 데 사용됩니다.

  • *ngFor는 컬렉션을 반복하고 여러 요소를 생성하는 데 사용됩니다.

이들은 Angular 템플릿 구문의 몇 가지 예일 뿐입니다. Angular의 템플릿 구문은 표현력이 풍부하고 읽기 쉽고 강력하도록 설계되어 선언적 방식으로 동적 및 대화형 사용자 인터페이스를 구축할 수 있습니다. 이를 통해 구성 요소 속성과 메서드를 템플릿에 원활하게 통합하여 데이터 바인딩, 이벤트 처리 및 조건부 렌더링을 용이하게 할 수 있습니다.

3. 디렉티브

Angular 디렉티브(Directives)는 Angular 프레임워크에서 HTML 요소의 동작이나 모양을 변경하고 확장하기 위해 사용되는 템플릿 지시자입니다. 디렉티브는 Angular 컴포넌트와 함께 사용되며, 템플릿에서 사용자 정의 요소로써 활용됩니다.

Angular 디렉티브는 크게 두 가지 유형으로 분류됩니다:

1) 구조 디렉티브 (Structural Directives)

  • 구조 디렉티브는 DOM의 구조를 조작하고 템플릿 내에서 요소를 추가하거나 제거하는 데 사용됩니다.

  • *ngIf, *ngFor, *ngSwitch 등이 구조 디렉티브에 해당합니다.

  • 구조 디렉티브는 HTML 요소에 * 기호를 추가하여 템플릿에 적용됩니다.

예시:

htmlCopy code<div *ngIf="showContent">내용이 표시됩니다.</div>
<ul>
  <li *ngFor="let item of items">{{ item }}</li>
</ul>

2) 속성 디렉티브 (Attribute Directives)

  • 속성 디렉티브는 HTML 요소의 속성을 변경하거나 확장하기 위해 사용됩니다.

  • ngClass, ngStyle, ngModel 등이 속성 디렉티브에 해당합니다.

  • 속성 디렉티브는 HTML 요소의 속성에 직접 적용됩니다.

예시:

htmlCopy code<div [ngClass]="{ 'highlight': isHighlighted }">강조됩니다.</div>
<button (click)="doSomething()">클릭하세요</button>

Angular 디렉티브는 컴포넌트와 마찬가지로 자체 로직과 데이터를 가질 수 있으며, 템플릿과 컴포넌트 간의 상호 작용을 제어하는 데 사용됩니다. 또한, Angular는 기본적으로 내장된 디렉티브를 제공하며, 사용자 정의 디렉티브를 생성하여 애플리케이션에 맞게 확장할 수도 있습니다. 디렉티브를 사용하여 HTML 요소의 동적인 동작과 모양을 조작하고, 재사용 가능한 컴포넌트를 생성하는 데 도움을 줍니다.

4. 서비스

Angular에서 서비스는 비즈니스 로직, 데이터 관리 및 공유 기능을 구현하는 데 중요한 역할을 합니다. 서비스는 애플리케이션 전체에서 재사용 가능한 기능을 캡슐화하고 제공하는 방법입니다. 다음은 Angular 서비스와 관련된 몇 가지 중요한 개념입니다.

1) 서비스 만들기

  • Angular의 서비스는 일반적으로 TypeScript 클래스로 생성되고 @Injectable() 데코레이터로 주석이 추가됩니다.

  • @Injectable() 데코레이터는 클래스를 서비스로 표시하고 종속성을 주입할 수 있도록 합니다.

2) 주입 가능 및 제공

  • @Injectable() 데코레이터는 클래스를 서비스로 사용할 수 있음을 나타내는 주입 가능으로 표시하는 데 사용됩니다.

  • @Injectable() 데코레이터의 providedIn 속성은 루트 인젝터를 서비스 공급자로 지정합니다.

  • 또는 providers 속성을 사용하여 구성 요소 수준 또는 모듈 수준에서 서비스를 제공할 수 있습니다.

3) 의존성 주입

  • Angular의 종속성 주입(DI) 시스템은 서비스 인스턴스를 구성 요소, 기타 서비스 또는 이를 필요로 하는 모든 Angular 구성에 주입하는 데 사용됩니다.

  • 서비스는 DI 시스템에 의해 자동으로 해결되고 주입되는 다른 서비스에 의존할 수 있습니다.

  • 종속성 주입은 느슨한 결합을 허용하고 재사용성을 촉진하며 종속성에 대한 제어를 제공하여 테스트를 더 쉽게 만듭니다.

4) 싱글톤 인스턴스

  • 기본적으로 Angular 서비스는 싱글톤 인스턴스입니다. 즉, 애플리케이션 전체에 서비스 인스턴스가 하나만 있음을 의미합니다.

  • Angular의 DI 시스템은 서비스의 단일 인스턴스를 생성하고 이를 요청하는 모든 구성 요소 및 다른 소비자 간에 공유합니다.

  • 이렇게 하면 데이터와 상태가 일관되고 불필요한 중복이 방지됩니다.

5) 서비스 메서드 및 속성

  • 서비스는 응용 프로그램의 다른 부분에 기능을 제공하는 메서드와 속성을 정의할 수 있습니다.

  • 서비스 메서드는 데이터 검색, 조작 또는 비즈니스 논리 작업을 수행할 수 있습니다.

  • 서비스 속성은 데이터를 보유하거나 구성 옵션을 제공할 수 있습니다.

6) 데이터 공유 및 커뮤니케이션

  • 서비스는 종종 구성 요소 간의 통신 및 데이터 공유 수단으로 사용됩니다.

  • 구성 요소는 공유 서비스와 상호 작용하여 데이터를 교환하거나 작업을 트리거할 수 있습니다.

  • 서비스는 통신의 중심점 역할을 하며 공유 데이터 또는 상태를 저장할 수 있습니다.

7) 외부 데이터 가져오기

  • 서비스는 일반적으로 API, 데이터베이스 또는 WebSocket 연결과 같은 외부 데이터 소스와 상호 작용하는 데 사용됩니다.

  • 서비스는 HTTP 요청을 하거나 데이터 검색 작업을 수행하기 위한 논리를 캡슐화합니다.

  • 구성 요소는 서비스에서 제공하는 데이터를 사용하여 UI에서 렌더링할 수 있습니다.

8) 라이프사이클 후크

  • 서비스는 'OnInit', 'OnDestroy' 등과 같은 Angular 수명 주기 후크를 구현하여 초기화 또는 정리 작업을 수행할 수 있습니다.

  • 수명 주기 후크를 사용하면 서비스가 리소스를 효율적으로 관리하고 Angular 프레임워크의 수명 주기 이벤트에 응답할 수 있습니다.

Angular 서비스는 확장 가능하고 유지 관리 가능한 애플리케이션을 구축하는 데 필수적인 부분입니다. 기능을 캡슐화 및 공유하고, 종속성을 관리하고, 구성 요소 간의 통신을 용이하게 하는 방법을 제공합니다. 서비스를 활용하면 더 쉽게 테스트하고 유지 관리할 수 있는 재사용 가능한 모듈식 코드를 만들 수 있습니다.

5. 의존성 주입 (Dependency Injection)

Angular의 의존성 주입(Dependency Injection, DI)은 Angular 프레임워크에서 컴포넌트, 서비스 및 기타 클래스 간의 의존성을 관리하는 메커니즘입니다. 의존성 주입을 통해 컴포넌트나 서비스가 필요로 하는 의존성을 자동으로 제공받을 수 있습니다.

Angular Dependency Injection의 주요 측면은 다음과 같습니다.

1) 종속성 주입 컨테이너

  • Angular에는 사용 가능한 서비스 및 해당 종속성의 레지스트리를 유지 관리하는 계층적 의존성 주입 컨테이너가 있습니다.

  • 컨테이너는 서비스 인스턴스를 생성 및 관리하고 이를 구성 요소 및 기타 서비스에 주입하는 역할을 합니다.

2) 주입 가능한 서비스

  • Angular의 서비스는 일반적으로 @Injectable() 데코레이터로 장식됩니다.

  • @Injectable() 데코레이터는 의존성 주입 후보로 클래스를 표시합니다.

  • Angular의 DI 시스템은 서비스의 의존성을 분석하고 필요한 인스턴스를 제공하여 이를 해결할 수 있습니다.

3) 공급자 등록

  • 공급자는 Angular에 등록되어 의존성(토큰)을 해당 구현에 매핑합니다.

  • 공급자는 구성 요소 수준, 모듈 수준 또는 응용 프로그램 수준의 다양한 수준에서 등록할 수 있습니다.

  • 공급자는 필요할 때 서비스 인스턴스를 만들고 주입하는 방법을 정의합니다.

4) 주입 토큰

  • 주입 토큰은 DI 시스템 내 종속성에 대한 고유 식별자 역할을 합니다.

  • 토큰은 클래스, 문자열 또는 InjectionToken 클래스를 사용하여 만든 사용자 정의 토큰일 수 있습니다.

  • 종속성이 요청되면 Angular의 DI 시스템은 토큰을 사용하여 해당 인스턴스를 찾아 제공합니다.

5) 종속성 주입

  • 종속성은 TypeScript의 생성자 매개 변수 구문을 사용하여 생성자에서 선언함으로써 구성 요소 또는 서비스에 주입할 수 있습니다.

  • DI 시스템은 등록된 공급자를 기반으로 종속성을 자동으로 해결하고 적절한 인스턴스를 주입합니다.

6. 의존성 주입 예시

Angular의 종속성 주입(DI) 개념을 작동 방식을 설명하는 몇 가지 예와 함께 살펴보겠습니다.

1) 서비스 종속성 주입

  • UserService 및 UserListComponent가 있는 시나리오를 고려하십시오.

  • UserService는 사용자 관련 데이터 및 작업을 처리합니다.

  • UserListComponent에서 UserService를 사용하여 사용자 데이터를 가져와야 합니다.

DI를 사용하면 UserService를 생성자에서 선언하여 UserListComponent에 주입할 수 있습니다.

import { Component } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user-list',
  template: `
    <ul>
      <li *ngFor="let user of users">{{ user.name }}</li>
    </ul>
  `
})
export class UserListComponent {
  users: User[];

  constructor(private userService: UserService) {
    this.users = this.userService.getUsers();
  }
}

Angular의 DI 시스템은 UserService의 인스턴스를 생성하고 이를 UserListComponent에 주입하여 종속성을 자동으로 해결합니다.

2) 구성 요소 계층 구조 및 계층적 주입

  • Angular는 계층적 주입을 지원합니다. 여기서 종속성은 구성 요소 계층 내의 다양한 수준에서 주입될 수 있습니다.

  • ParentComponent와 ChildComponent가 있고 둘 다 공통 DataService에 액세스해야 하는 시나리오를 고려해 보겠습니다.

  • 상위 구성 요소 수준에서 DataService를 제공함으로써 Angular의 DI 시스템은 동일한 DataService 인스턴스가 ParentComponent 및 해당 하위 구성 요소에서 공유되도록 합니다.

import { Component } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-parent',
  template: `
    <h1>Parent Component</h1>
    <app-child></app-child>
  `,
  providers: [DataService] // DataService provided at the parent component level
})
export class ParentComponent {}

@Component({
  selector: 'app-child',
  template: `
    <h2>Child Component</h2>
  `
})
export class ChildComponent {
  constructor(private dataService: DataService) {}
}

ParentComponent와 ChildComponent 모두 DataService의 동일한 인스턴스에 액세스할 수 있습니다.

3) 사용자 정의 제공자 구성

  • Angular를 사용하면 주입 동작을 제어하거나 대체 구현을 제공하도록 사용자 지정 공급자를 구성할 수 있습니다.

  • 메시지를 기록하는 LoggerService가 있고 LoggerService의 사용자 지정 구현을 제공하려고 한다고 가정해 보겠습니다.

  • 다른 구현을 제공하기 위해 공급자 객체를 정의하고 useClass 속성을 지정하여 사용자 지정 공급자를 생성할 수 있습니다.

    import { Component, Injectable } from '@angular/core';
    
    @Injectable()
    export class LoggerService {
      log(message: string) {
        console.log(`Logging: ${message}`);
      }
    }
    
    @Component({
      selector: 'app-example',
      template: `
        <button (click)="logMessage()">Log Message</button>
      `,
      providers: [
        { provide: LoggerService, useClass: CustomLoggerService }
      ]
    })
    export class ExampleComponent {
      constructor(private logger: LoggerService) {}
    
      logMessage() {
        this.logger.log('Hello, Angular!');
      }
    }
    
    @Injectable()
    export class CustomLoggerService {
      log(message: string) {
        console.log(`Custom Logging: ${message}`);
      }
    }

위 예시에서 ExampleComponent는 기본 LoggerService가 아닌 CustomLoggerService와 함께 제공됩니다.

이러한 예는 Angular의 DI 시스템이 어떻게 의존성을 자동으로 해결하고 주입하여 구성 요소와 서비스를 종속성에서 분리할 수 있는지 보여줍니다. DI를 활용하면 응용 프로그램 전체에서 종속성을 쉽게 관리하고 공유하여 모듈식 및 재사용 가능한 코드를 촉진할 수 있습니다.

7. HTTP통신

Angular에서 HTTP 통신 및 데이터 관리는 일반적으로 내장된 HttpClient 모듈을 사용하여 처리됩니다. HttpClient 모듈은 원격 API와 상호 작용하고 HTTP 요청을 수행하는 편리한 방법을 제공합니다. 다음은 Angular가 HTTP 통신 및 데이터 관리를 처리하는 방법에 대한 개요입니다.

1) HttpClient 모듈 가져오기

  • HttpClient 모듈을 사용하려면 사용하려는 모듈의 @angular/common/http에서 import해야 합니다.

  • 가져오기 문: @angular/common/http'에서 { HttpClient } 가져오기;

2) HttpClient의 의존성 주입

  • HTTP 요청을 하려는 구성 요소 또는 서비스에서 생성자에 HttpClient 의존성을 삽입합니다.

  • Angular의 종속성 주입 시스템은 HttpClient 인스턴스를 제공합니다.

  • 예: 생성자(비공개 http: HttpClient) { }

3) HTTP 요청 만들기

  • HttpClient는 GET, POST, PUT, DELETE 등과 같은 다양한 유형의 HTTP 요청을 만드는 방법을 제공합니다.

  • 이러한 메소드를 사용하여 원격 API와 상호 작용하고 데이터를 송수신할 수 있습니다.

  • GET 요청 예

    this.http.get<User[]>('https://api.example.com/users')
      .subscribe(users => {
        // Handle the response
        console.log(users);
      }, error => {
        // Handle any errors
        console.error(error);
      });

4) 응답 처리

  • HTTP 요청은 응답을 처리하기 위해 구독할 수 있는 Observable을 반환합니다.

  • map, filter, catchError 등과 같은 RxJS 연산자를 사용하여 응답 데이터를 변환하거나 조작할 수 있습니다.

  • 응답 데이터 매핑의 예:

    this.http.get<User[]>('https://api.example.com/users')
      .pipe(
        map(users => users.filter(user => user.age > 18))
      )
      .subscribe(filteredUsers => {
        console.log(filteredUsers);
      });

5) 오류 처리

  • HTTP 요청을 할 때 오류를 정상적으로 처리하는 것이 중요합니다.

  • RxJS의 catchError 연산자를 사용하여 오류를 처리하고 폴백 동작을 제공할 수 있습니다.

  • 오류 처리의 예:

    this.http.get<User[]>('https://api.example.com/users')
      .pipe(
        catchError(error => {
          console.error(error);
          return throwError('An error occurred. Please try again later.');
        })
      )
      .subscribe(users => {
        // Handle the response
        console.log(users);
      });

6) 데이터 전송

  • GET 요청 외에도 post, put, patch 등의 메서드를 사용하여 HTTP 요청으로 데이터를 보낼 수도 있습니다.

  • 두 번째 매개변수로 전송할 데이터를 이 메서드에 전달할 수 있습니다.

  • POST 요청으로 데이터를 전송하는 예:

    const newUser: User = { name: 'John Doe', age: 25 };
    
    this.http.post<User>('https://api.example.com/users', newUser)
      .subscribe(response => {
        console.log(response);
      });

Angular의 'HttpClient' 모듈은 요청 헤더, 쿼리 매개변수, 인터셉터 등과 같은 추가 기능을 제공하여 HTTP 통신 및 데이터 관리를 향상시킵니다. Angular의 구성 요소 및 서비스 아키텍처와 잘 통합되어 원격 API에서 데이터를 원활하게 검색하고 업데이트할 수 있습니다.

8. 상태 관리 패턴

Angular의 상태 관리 패턴은 서로 다른 구성 요소 간에 애플리케이션의 상태를 관리하고 동기화하는 것과 관련이 있습니다. 응용 프로그램의 다양한 부분에서 액세스하고 수정할 수 있는 중앙 집중식 데이터 저장소를 구성하고 유지 관리하는 데 도움이 됩니다. 인기 있는 Angular용 상태 관리 라이브러리 중 하나는 Redux 패턴을 구현하는 NgRx입니다. 다음은 Angular의 상태 관리 패턴과 NgRx를 활용하는 방법에 대한 소개입니다.

1) 리덕스 패턴:

  • NgRx는 Angular 애플리케이션용 Redux 패턴을 구현한 것입니다.

  • Redux는 응용 프로그램 상태가 스토어라는 불변 데이터 구조에 저장되는 단방향 데이터 흐름을 따릅니다.

  • 액션은 상태 변화를 설명하기 위해 발송되며 리듀서라는 순수 함수가 이러한 액션을 처리하여 새로운 상태를 생성합니다.

2) NgRx 개념

  • NgRx는 상태 관리를 위한 몇 가지 핵심 개념을 소개합니다.

    • Store: 애플리케이션 상태에 대한 중앙 저장소입니다.

    • Actions: 상태를 수정하려는 이벤트 또는 의도를 나타내는 일반 JavaScript 개체입니다.

    • 감속기: 현재 상태와 작업을 수행하고 새 상태를 반환하는 순수 함수입니다.

    • 효과: 액션에 반응하고 비동기 작업과 같은 부작용을 수행합니다.

    • 선택기: 상태에서 특정 데이터를 추출하는 구성 가능한 기능.

3) NgRx의 이점

  • 예측 가능한 상태 변경: NgRx는 단방향 데이터 흐름을 적용하여 상태 변경을 더 쉽게 이해하고 디버깅할 수 있도록 합니다.

  • 중앙 집중식 상태: 스토어는 단일 위치에 애플리케이션 상태를 유지하여 예측 가능한 방식으로 모든 구성 요소에 액세스할 수 있도록 합니다.

  • 불변 상태: 상태는 불변이므로 순수한 기능을 통해 변경이 이루어지고 의도하지 않은 변경이 방지됩니다.

  • 시간 이동 디버깅: NgRx를 사용하면 동작을 재생하고 다른 시점에서 상태를 볼 수 있어 디버깅에 도움이 됩니다.

  • 코드 구성: NgRx는 관심사를 분리하고 구성 요소 결합을 줄임으로써 구조화된 모듈식 코드베이스를 촉진합니다.

4) NgRx 시작하기

  • Angular 애플리케이션에서 NgRx를 활용하려면 필수 패키지인 @ngrx/store, @ngrx/effects@ngrx/entity를 설치해야 합니다.

  • 상태 변경을 나타내는 작업, 이러한 작업을 처리하는 리듀서 및 부작용을 처리하는 효과를 정의합니다.

  • Angular 모듈에서 제공되는 StoreModule.forRoot() 함수를 사용하여 중앙 저장소를 만듭니다.

  • 구성 요소에 'Store'를 삽입하여 상태에 액세스하고 수정하고 선택기를 사용하여 상태에서 특정 데이터를 추출합니다.

NgRx는 Angular 애플리케이션에서 복잡한 상태를 관리하기 위한 강력하고 확장 가능한 솔루션을 제공합니다. 유지 관리 용이성, 코드 구성 및 예측 가능한 데이터 흐름을 촉진합니다. 그러나 NgRx 채택을 결정하기 전에 애플리케이션의 복잡성을 평가하는 것이 중요합니다. 소규모 애플리케이션에는 이러한 포괄적인 상태 관리 솔루션이 필요하지 않을 수 있기 때문입니다.

9. 테스팅

테스트는 애플리케이션의 정확성과 품질을 보장하기 위한 Angular 개발의 필수적인 부분입니다. Angular는 단위 테스트, 통합 테스트 및 종단 간 테스트를 지원하는 강력한 테스트 프레임워크를 제공합니다. 다음은 Angular 테스트에 대한 개요와 다양한 유형의 테스트를 수행하는 방법입니다.

1) 테스트 프레임워크

  • Angular는 즉시 사용할 수 있는 Jasmine 및 Karma와 같은 여러 테스트 프레임워크를 지원합니다.

  • Jasmine은 테스트 작성을 위한 BDD(Behavior-Driven Development) 프레임워크이며, Karma는 다양한 브라우저에서 테스트를 실행하는 테스트 러너입니다.

2) 단위 테스트

  • 단위 테스트는 구성 요소, 서비스 및 지시문과 같은 개별 코드 단위를 격리된 상태에서 테스트하는 데 중점을 둡니다.

  • Angular의 테스트 프레임워크는 TestBedComponentFixture와 같은 유틸리티를 제공하여 구성 요소를 만들고 테스트합니다.

  • describe, beforeEachit과 같은 Jasmine의 테스트 기능을 사용하여 테스트 스위트 및 테스트 사례를 정의할 수 있습니다.

3) 구성 요소 테스트

  • 구성 요소 테스트에는 Angular 구성 요소의 동작, 렌더링 및 상호 작용 테스트가 포함됩니다.

  • 'TestBed.createComponent()'를 사용하여 구성 요소의 인스턴스를 생성하고 해당 속성, 메서드 및 HTML 템플릿을 테스트할 수 있습니다.

  • fixture.detectChanges()를 사용하여 변경 감지를 트리거하고 구성 요소의 보기를 업데이트합니다.

4) 서비스 테스트

  • 서비스는 단위 테스트를 사용하여 독립적으로 테스트할 수 있습니다.

  • 모의 종속성을 제공하거나 Angular의 종속성 주입 시스템을 사용하여 테스트에 필요한 종속성을 주입할 수 있습니다.

  • 서비스의 메서드, 속성 및 다른 서비스 또는 API와의 상호 작용을 테스트합니다.

5) 통합 테스트

  • 통합 테스트에는 여러 구성 요소, 서비스 및 모듈 간의 상호 작용 테스트가 포함됩니다.

  • 'TestBed.createComponent()'를 사용하여 테스트 베드를 만들고 애플리케이션의 다른 부분 통합을 시뮬레이션합니다.

  • 구성 요소와 서비스 간의 통신 및 동작을 테스트합니다.

6) DOM 상호 작용 테스트

  • Angular의 테스트 프레임워크는 DOM 상호 작용 및 이벤트를 테스트하기 위한 유틸리티를 제공합니다.

  • DebugElementBy를 사용하여 구성 요소 템플릿의 요소를 쿼리하고 상호 작용합니다.

  • 클릭, 입력 또는 제출과 같은 이벤트를 시뮬레이션하고 예상되는 동작을 테스트합니다.

7) 비동기 테스트

  • Angular는 약속, 관찰 가능 항목 및 HTTP 요청과 같은 비동기 코드 테스트를 지원합니다.

  • Angular의 asyncfakeAsync 유틸리티를 활용하여 테스트에서 비동기 작업을 처리합니다.

  • tick()을 사용하여 시간 경과를 시뮬레이션하고 비동기 작업이 완료될 때까지 기다립니다.

8) 종단 간 테스트

  • Angular는 E2E(end-to-end) 테스트를 위한 'Protractor' 도구를 제공합니다.

  • Protractor를 사용하면 사용자 상호 작용을 시뮬레이션하는 테스트를 작성하고 처음부터 끝까지 애플리케이션의 동작을 확인할 수 있습니다.

  • E2E 테스트는 TypeScript 또는 JavaScript로 작성되며 실제 브라우저에서 실행할 수 있습니다.

Angular의 테스트 프레임워크는 애플리케이션의 다양한 측면을 테스트하기 위한 포괄적인 도구 및 유틸리티 세트를 제공합니다. 테스트를 작성하면 애플리케이션이 예상대로 작동하는지 확인하고 회귀를 방지하며 높은 수준의 코드 품질을 유지할 수 있습니다. 최대 테스트 적용 범위를 보장하기 위해 기능을 구현하기 전에 테스트를 작성하는 테스트 기반 개발(TDD) 접근 방식을 따르는 것이 좋습니다.

10. 최적화

Angular 애플리케이션의 성능을 최적화하는 것은 원활한 사용자 경험과 효율적인 리소스 활용을 보장하는 데 중요합니다. 다음은 모듈 분할 및 지연 로딩을 포함하여 Angular 애플리케이션의 성능을 최적화하기 위해 사용할 수 있는 몇 가지 기술과 전략입니다.

1) AOT 컴파일 (Ahead-of-Time Compilation)

  • AOT 컴파일은 빌드 과정에서 템플릿과 컴포넌트를 미리 컴파일하여 런타임에서의 컴파일 필요성을 없앱니다.

  • AOT 컴파일을 활성화하면 애플리케이션의 로드 속도가 향상되며 초기 번들 크기가 줄어듭니다.

  • Angular CLI의 --aot 플래그를 사용하거나 Angular CLI 설정에서 AOT 컴파일을 활성화할 수 있습니다.

2) 모듈 분할과 지연 로딩 (Module Splitting and Lazy Loading)

  • 애플리케이션을 작은 모듈로 분할하고 지연 로딩을 사용하여 필요할 때만 모듈을 로드할 수 있도록 합니다.

  • 초기 로드 시 필요하지 않은 기능 모듈은 따로 분리하여 개별적으로 로드될 수 있도록 합니다.

  • 이를 통해 초기 번들 크기를 줄이고 애플리케이션의 시작 시간을 최적화할 수 있습니다.

3) 변경 감지 전략 최적화 (Change Detection Optimization)

  • Angular의 변경 감지(Change Detection)는 애플리케이션의 성능에 영향을 미칠 수 있습니다.

  • 컴포넌트의 변경 감지 전략을 ChangeDetectionStrategy.OnPush로 설정하여 성능을 최적화합니다.

  • 옵저버블(Observable) 데이터 스트림을 활용하고 불변성을 유지하는 등 스마트한 변경 감지를 구현합니다.

4) 프로덕션 모드 사용 (Production Mode)

  • 애플리케이션을 프로덕션 모드로 실행하여 성능을 향상시킬 수 있습니다.

  • enableProdMode() 함수를 사용하여 프로덕션 모드로 전환합니다.

  • 프로덕션 모드에서는 추가적인 검사와 디버깅 기능이 비활성화되어 애플리케이션의 실행 속도가 향상됩니다.

5) 효율적인 데이터 바인딩

  • 템플릿에서 사용하는 데이터 바인딩을 최적화하여 불필요한 감시 대상을 제거합니다.

  • 복잡한 표현식을 템플릿에서 직접 사용하는 대신 컴포넌트에서 계산된 값을 바인딩합니다.

  • 큰 배열이나 객체를 반복문(*ngFor)으로 렌더링할 때는 변경 감지 성능에 영향을 줄 수 있으므로 주의가 필요합니다.

6) 서버 사이드 렌더링 (Server-Side Rendering, SSR)

  • SSR을 통해 초기 로딩 속도를 향상시킬 수 있습니다.

  • 서버에서 초기 뷰를 렌더링하여 완전히 렌더링된 페이지를 브라우저로 전달하므로 초기 로딩 속도가 개선됩니다.

  • Angular Universal을 사용하여 SSR을 구현할 수 있습니다.

7) 외부 리소스 최적화

  • 이미지, CSS, JS 파일 등의 외부 리소스를 최적화합니다.

  • 이미지의 크기를 최소화하고 압축 형식을 사용합니다.

  • 필요하지 않은 외부 라이브러리를 제거하거나 경량화된 버전을 사용합니다.

8)성능 모니터링과 프로파일링

  • 성능 모니터링 도구를 사용하여 애플리케이션의 성능을 지속적으로 모니터링하고 프로파일링합니다.

  • Lighthouse, WebPageTest, Chrome 개발자 도구 등의 도구를 사용하여 성능 메트릭을 확인하고 성능 향상을 위한 작업을 수행합니다.

이러한 최적화 기법을 조합하여 Angular 애플리케이션의 성능을 향상시킬 수 있습니다. 성능 향상은 사용자 경험을 향상시키고 서버 및 클라이언트 자원의 효율적인 활용을 도모하는 데 중요합니다. 성능 최적화는 지속적으로 모니터링하고 테스트하여 애플리케이션의 성능을 개선하는 데 도움이 됩니다.

Last updated