角度のある世界におけるテスト駆動開発
23718 ワード
待って!TDDとは
だから、あなたはこのTDDのことについて聞いて、それを使用して起動したいが、理由がわからない.心配しないでください、インターネット救助に!しかし、まず、TDDは何ですか?
TDDはテストドリブン開発を表し、コードを書く方法です.これは、最初にテストを書くということを意味します.これは赤緑のアプローチとも呼ばれます.長い話短い、それはテストによって駆動される開発です.
小さな例:2つの数字を追加するメソッドを書きたいとしましょう.さて、メソッドを実装する代わりに、テストを最初に書きます.
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;
}
そして今テストはパスします.今、それはかなり満足している、右?
したがって、これはいくつかあります.
ここのキーワードは
今、角度と我々のコンポーネントに戻る
だから、今、あなたはTDDは何についてのアイデアがあります.次の停止は、コンポーネントで使用します.このポストのために、私はあなたに角度の基本的な理解があると仮定します.
私はテストのための冗談を使用しますが、原則は同じです.
我々の例については、映画でリストを作成できる架空のアプリケーションを使用してみましょう.今、空間と時間のどこかに、我々はまた、ユーザーが彼/彼女の好きな映画を見ることができるページが欲しいと決めます.だから、さらにADOなしで、それを構築しましょう!
まず、コンポーネントを生成します.
ng g c favorite-movies
さて、これはコンポーネントを生成します.では、まず何をしたいですか?我々は好きな映画のようなタイトルを追加します.しましょう!WAAAAIT!何を議論しましたか.テストを書いて、それを修正するコードを書きます.
だから、それはどのように見えるでしょうか?このような
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');
});
});
私たちはレンダリングのための新しい記述ブロックを作成しました、そして、そこで、我々はH 1タグがある、そして、それが正しい内容を持っていることをチェックする新しいテストを加えました.今、我々はテストを実行し、大きな驚き、それは失敗!フレットしないでください.
<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>
これは私たちのテンプレートに追加されます.うん!テストは今パス!neeeeext!
データが実際に非同期的にサービスから来るならば、どうですか?
テストを調整しましょう
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をする時間🐴.waaaaait!エラーがある場合は?
OK , OK ,何か失敗した場合には適切に扱われるようにいくつかのテストを書きましょう.
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>
今、すべてのハードワークの後、我々はデータを取得し、エラーを処理し、我々がそれを期待するすべてをレンダリングする非同期サービスを使用して完全に動作するコンポーネントを持っている.今、いくつかの目のお菓子のための時間:
かなりクールな右?
さて、これが動作するためには、サービスを実装する必要はありません.それはちょうど存在しなければならなくて、GetFavoritemoviesと呼ばれているメソッドを持っていなければなりません.
包む
私は知っている、私は知っている、たくさんの単語.私は重要な情報を省略することなく私はできるだけ簡潔にしようとしました.口は重宝手は宝.これは私の最初の記事です.うまくいけば、次の1つでは、アングルサービスのテストについて話します.もちろんTDD.
このプログラムを楽しんでください📺. 次のいずれかを参照してください!
Reference
この問題について(角度のある世界におけるテスト駆動開発), 我々は、より多くの情報をここで見つけました https://dev.to/utukku/test-driven-development-in-an-angular-world-3h8gテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol