각도 세계에서의 테스트 구동 개발

기다리다TDD란 무엇입니까?


그래서 이 TDD의 물건을 계속 듣고 사용하려고 했지만 왜 그런지 모르겠어요.걱정하지 마라, 인터넷이 구원하러 온다!하지만 우선 TDD란 무엇입니까?
TDD는 테스트 구동 개발을 대표하며 코드를 작성하는 방식이다.이것은 테스트를 먼저 작성하고 실패한 후에 코드를 작성하여 통과시키는 것을 의미합니다.이것도 빨간색-녹색 방법이라고 부른다.긴 말은 짧게 말하지만, 그것은 테스트 구동의 개발이다.
예를 들어 두 개의 숫자를 덧붙이는 방법을 쓰고 싶다고 가정해 보세요.현재 이 방법을 실행하지 않고 테스트를 작성합니다.
it('should add the values', () => {
  const result = addValues(2, 4);

  expect(result).toBe(6);
});

let addValues = (value1, value2) {}
테스트를 실행했는데 실패했습니다.

이제야 문제의 원인을 알 수 있으므로 다음을 수행할 수 있습니다.
it('should add the values', () => {
  const result = addValues(2, 4);

  expect(result).toBe(6);
});

let addValues = (value1, value2) {
  return value1 + value2;
}
이제 테스트가 통과되었습니다.

지금, 이것은 매우 만족스럽다, 그렇지?
따라서 다음과 같은 작업을 수행할 수 있습니다.
  • 코드가 테스트를 거쳤는지 확인하십시오. 그러면 sprint의 마지막 이틀 동안 작성한 모든 코드를 테스트할 필요가 없습니다(이것은 영원히 발생하지 않습니다)
  • 실용적인 방식으로 코드를 작성해야 한다.YAGNI라는 것이 있다. 그것은 개발자에 대한 사고이며, 기후변화와 세계의 기아 문제를 다음 코드로 해결하려고 시도하는 것이다.대부분의 경우 코드가 너무 복잡하고 진정한 장점이 없다는 것은 확실하다.
  • 이러한 방식으로 특성을 작성했을 때 모든 테스트가 통과된 것을 보았습니다. 이것은 당신에게 자신감을 주었습니다. 만약/재구성할 때 테스트가 통과된다면 어떤 것도 파괴하지 않을 것입니다.당신은 간단한 드래그 요청을 통해 제품을 파괴하는 것을 몇 번이나 두려워했습니까?느낌은 다음과 같다.
  • 마지막이지만 가장 중요하지 않은 점은 아니다. 이 모든 것은 색깔과 관련이 있다!색깔을 보니 우리를 기쁘게 한다.어떤 일들이 실패하고 지나가는 것을 보면 우리는 더욱 즐겁다.
  • 3개월과 500번의 테스트를 거친 후에 우리는 개발 중인 제품에 대해 진정한 자신감을 가지게 되었다.
    여기서 키워드는 자신감입니다.

    이제 각도와 우리의 분량으로 돌아가


    이제 TDD가 뭔지 알겠어.다음 정거장에서 우리 구성 요소에서 그것을 사용하십시오.이 글에 대해 나는 네가 Angular에 대해 기본적으로 알고 있다고 가정하기 때문에 나는 그것이 어떻게 작동하는지 상세하게 소개하지 않을 것이다.
    나는 테스트에서 Jest를 사용할 것이다. 그러나 원칙은 같다.
    우리의 예에서, 우리는 허구적인 응용 프로그램을 사용하여 영화 목록을 만들 것이다.현재, 공간과 시간의 어느 곳에서, 우리는 사용자가 그/그녀가 가장 좋아하는 영화를 볼 수 있도록 페이지를 하나 더 필요로 하기로 결정했다.그러니 더 이상 말할 필요가 없다. 우리가 그것을 구축하자!
    먼저 구성 요소를 생성합니다.
    ng g c favorite-movies
    
    이제 구성 요소가 생성됩니다.그럼 우리 먼저 뭘 해야 하는지 봅시다.우리는 가장 좋아하는 영화 같은 제목을 추가하고 싶다.우리 시작합시다!
    와!우리는 무엇을 토론했습니까?테스트를 작성한 다음 그것을 복구하는 코드를 작성합니다.
    그럼, 그건 어떤 모습일까요?다음과 같이 하십시오.
      describe('Render', () => {
        beforeEach(() => {
          fixture.detectChanges();
        });
    
        it('should have a title', () => {
          const titleElements = fixture.debugElement.queryAll(By.css('h1'));
          expect(titleElements.length).toBe(1);
          expect(titleElements[0].nativeElement.innerHTML).toBe('Favorite movies');
        });
      });
    
    우리는 렌더링을 위해 새로운 descripe 블록을 만들었고, 그 안에 h1 표시가 있는지, 그리고 정확한 내용이 있는지 확인하는 새로운 테스트를 추가했습니다.
    지금, 우리는 테스트를 실행했는데, 놀랍게도 그것은 실패했다.걱정하지 마세요. 우리는 그것을 해결할 수 있습니다.
    <h1>Favorite movies</h1>
    
    HTML 템플릿에 추가했습니다. 이제 테스트를 통과했습니다!
    축하TDD 방식으로 첫 번째 코드를 작성했습니다.시간을 내서 자신의 등을 두드리다.잘하다이제 멈춰.우리는 아직 더 많은 일을 해야 한다.
    다음은 HTML 형식으로 표시되는 영화 목록을 테스트해 보려고 합니다.그럼, 우리는 어떻게 해야 합니까?우리는 그것을 위해 테스트를 하나 썼다.
    
    const favoriteMoviesToUse: Movie[] = [
      { title: 'Interstellar' } as Movie,
      { title: 'The big Lebowski' } as Movie,
      { title: 'Fences' } as Movie
    ];
    
    describe('FavoriteMoviesComponent', () => {
      beforeEach(() => {
        fixture = TestBed.createComponent(FavoriteMoviesComponent);
        component = fixture.componentInstance;
        component.favoriteMovies = favoriteMoviesToUse;
      });
    
      describe('Render', () => {
    
        it('show all the favorite movies', () => {
          const movieElements = fixture.debugElement.queryAll(By.css('.movie'));
          expect(movieElements.length).toBe(favoriteMoviesToUse.length);
        });
    
         it('should show the movie titles', () => {
          const movieElements = fixture.debugElement.queryAll(By.css('.movie'));
          movieElements.forEach((movieElement: DebugElement, index) => {
             expect(movieElement.nativeElement.innerHTML).toContain(favoriteMoviesToUse[index].title);
          });
        });
      });
    });
    
    여기서 우리는 구성 요소에 새로운 @Input () 속성을 추가했습니다. 우리는 새로운 영화 목록을 만들고 이를 입력으로 구성 요소에 전달합니다.그리고 HTML이 클래스 영화의 정확한 수량의 요소를 포함하는지, 그리고 모든 영화 제목을 표시하는지 테스트하고 있습니다.
    물론 이 테스트는 실패했다.그렇다면 다음과 같이 하십시오.
    <div class="movie" *ngFor="let movie of favoriteMovies">
      {{ movie.title }}
    </div>
    
    이것은 우리가 템플릿에 추가한 내용이다.네!지금 테스트 통과!
    neeeext!
    만약 우리의 데이터가 실제로 비동기적인 서비스에서 나온다면?
    테스트를 조정해 보겠습니다.
    describe('FavoriteMoviesComponent', () => {
      let component: FavoriteMoviesComponent;
      let fixture: ComponentFixture<FavoriteMoviesComponent>;
      let favoriteMovieService: FavoriteMoviesService;
    
      beforeEach(() => {
        fixture = TestBed.createComponent(FavoriteMoviesComponent);
        component = fixture.componentInstance;
        favoriteMovieService = TestBed.get(FavoriteMoviesService);
        jest.spyOn(favoriteMovieService, 'getFavoriteMovies').mockReturnValue(of(favoriteMoviesToUse));
      });
    
      describe('Getting the movies', () => {
        it('should get the movies from the service', () => {
          fixture.detectChanges();
          expect(favoriteMovieService.getFavoriteMovies).toHaveBeenCalled();
        });
      });
    });
    
    현재, 우리의 테스트 가설은 서비스에 주입되었다.우리가 하는 일은 아날로그 응답을 하고 서비스가 호출되었는지 확인하는 것이다.테스트 실패, 복구합시다!
    export class FavoriteMoviesComponent implements OnInit {
      favoriteMovies$: Observable<Movie[]>;
      constructor(private favoriteMovieService: FavoriteMoviesService) {}
    
      ngOnInit() {
        this.favoriteMovies$ = this.favoriteMovieService.getFavoriteMovies();
      }
    }
    
    이제 구성 요소는 @Input() 대신 서비스를 사용합니다.마지막 퍼즐은 템플릿입니다.
    <ng-container *ngIf="(favoriteMovies$ | async); let favoriteMovies">
      <div class="movie" *ngFor="let movie of favoriteMovies">
        {{ movie.title }}
      </div>
    </ng-container>
    
    그래서 이제 우리는 서비스에서 데이터를 얻고 렌더링할 수 있는 완전한 작업 구성 요소가 생겼다.우리는 또 무엇을 필요로 합니까?아무것도 없다집에 가서 붉은 악마 구원2를 할 때가 됐어요.🐴.
    와!만약 잘못이 있으면 어떻게 합니까?
    예, 예, 몇 가지 테스트를 작성하여 고장이 발생한 상황에서 정확하게 처리할 수 있도록 하겠습니다.
        it('should show an error if getting the movies fail', () => {
          const errorToThrow = 'User not found';
          jest
            .spyOn(favoriteMovieService, 'getFavoriteMovies')
            .mockReturnValue(throwError(errorToThrow));
    
          fixture.detectChanges();
    
          const errorElement = fixture.debugElement.queryAll(By.css('.error'));
          expect(errorElement.length).toBe(1);
          expect(errorElement[0].nativeElement.innerHTML).toContain(errorToThrow);
        });
    
        it('should not show an error if getting the movies succeeds', () => {
          fixture.detectChanges();
    
          const errorElement = fixture.debugElement.queryAll(By.css('.error'));
          expect(errorElement.length).toBe(0);
        });
    
    따라서 우리는 가장 좋아하는 영화를 얻는 데 실패했을 때 오류를 표시하고, 모든 것이 계획대로 진행되면 오류를 숨기기를 바란다.
    우리가 필요로 하는 것은 구성 요소의 오류를 포착하는 것이다.
      ngOnInit() {
        this.favoriteMovies$ = this.favoriteMovieService.getFavoriteMovies().pipe(
          catchError((error: any) => {
            this.error = error;
    
            return of([]);
          })
        );
      }
    
    템플릿에 오류가 표시됩니다.
    <div class="error" *ngIf="error">
      {{ error }}
    </div>
    
    현재, 우리의 모든 노력을 통해 우리는 비동기적인 서비스로 데이터를 얻고 오류를 처리하며 우리가 기대하는 모든 것을 보여주는 완전한 작업 구성 요소를 가지게 되었다.
    이제 눈을 즐겁게 할 때가 되었다.

    멋있죠?
    현재, 그 일을 하기 위해서, 당신은 이 서비스를 실현할 필요가 없습니다.그것은 단지 존재하고 getFavorite Movies라는 방법을 가지고 있을 뿐이다.

    총결산


    알아요, 알아요, 단어가 많아요.나는 가능한 한 간결하게 어떤 중요한 정보도 빠뜨리지 않았다.말하기는 쉬워도 하기는 어렵다.이것은 나의 첫 번째 Dev.to 문장이기 때문에 나는 아직 공부하고 있다.다음 절에서 우리는 테스트 각도 서비스에 대해 토론할 것이다.당연히 TDD지.
    이 프로그램 좋아해주셨으면 좋겠어요.📺. 다음에 봐요!

    좋은 웹페이지 즐겨찾기