TDD
angular

Angularを使ってテスト駆動開発しようとしたときの備忘録

はじめに

テスト駆動開発について勉強する機会がありました。
Angularのテストについても勉強する機会があったので、Angularを使ってテスト駆動開発を実験。
その時の備忘録。

環境

  • Windows10
  • Angular 5.2
  • Angular-cli 1.6.5

Angularを使ったテスト

テストの種類

  • ユニットテスト =単体テスト  個々の構成要素を単体で確認
  • E2Eテスト =インテグレーションテスト  サーバーサイドとクライアントサイドの協調動作の確認

Karma+Jasmineによるテスト

Karma

 これを起動すると、Webサーバーが生成されます。
 そのあと自動的にブラウザが起動し、生成したWebサーバーを通じて、そのブラウザがテストを開始。
 Angular-cliを使っていると自動的にインストールされるのでおすすめ。

 image.png

Jasmine

 テストコードの記述、テスト結果の確認、モックライブラリなどの機能を備えたテスティングフレームワーク。
 基本的にテストコードを記述するファイス名は末尾を".spec"として./appに作成が推奨。
 こちらもAngular-cliを使うと自動的に作成されてる。便利。

image.png

テストコードかいてみる

app.component.spec.ts
describe('テスト',() => {
  beforeEach(() =>{
    //初期化処理
  });

it('1+1のテスト',() => {
  expect(1+1).toEqual(2);
  });
});

今回は1+1が2であることを確認するテストを書きました。
まず、describeメソッドで全体を囲むことで、テストのまとまりを表します。
beforeEachメソッドは、初期化処理が必要な場合に使用するので、省略可能です。
itメソッドでは、個々のテストをかいていきます。
expoectの中にはテスト対象のコードを、
toEqualの中には期待する値をかきます。

toEqualはアサーションメソッドとよばれ、toEqualの他にもいっぱいあります

テスト実行

npm testコマンド実行でできます。

テストが成功するとこちらの画像がでます。
 image.png

デフォルトのテストが3件あったので、テストは全4件です。

上のコードを次のようにかえて失敗させてみます。

app.component.spec.ts
describe('テスト',() => {
  beforeEach(() =>{
    //初期化処理
  });

it('1+1のテスト',() => {
  expect(1+1).toEqual(3);
  });
});

 image.png

テスト駆動開発について

TDDサイクル

とっても簡単に言うと、
1. 失敗するテストをかく。
2. テストが成功するように実装する。
3. テストが成功したままきれいなコードをかく。(リファクタリング)
を繰り返すことらしいです。

ポイント
・テストはたくさんではなく1つかく。
・ステップ2ではテストが成功することだけを考える。
・テストが通る状態を維持する。

Angularを使ったテスト駆動開発してみると

FizzBazzを例に…

t_wadaさんのde:codeの講演にて、FizzBazzを使った例でデモをされていたので、
同じ例を使ってAngularでテスト駆動してみます。

まず目標を考えます。
今回の目標は以下6つに分けられます。細かくわけることが大事です。
1. 数を文字列にして返す
2. 3の倍数の時は数の代わりにFizzと返す
3. 5の倍数の時はBuzzと返す
4. 3と5両方の倍数の場合には「FizzBuzz」と返す
5. 1から100までの数
6. プリントする

さっそく一つ目の目標からテストをかいてみます。

数字を文字列に変換

appcomponent.spec.ts
describe('数字を文字列にして返す', () =>{
   beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent //テストしたいコンポーネントを宣言
      ],
    }).compileComponents();
  }));
  it('1を文字列1で返す',async(() => {
    //準備
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    //検証
    expect(app.numtest).toEqual('1');
  }));
});

テストコードを書くときは検証部分から埋めていき、
下から上にコードを書くとよいそうです。

テスト実行。
まだ何も実装してないので怒られます。

 image.png

テストコードが正しいことをテストします。
テストのてすと。

appcomponent.ts
export class AppComponent {
  title = 'app';
  numtest = Numtest(1);
  };

function Numtest(i: number): string {
    return '1';
  }

image.png

実装します。

export class AppComponent {
  title = 'app';
  numtest = Numtest(1);
  };

function Numtest(i: number): string {
    return i.toString();
  }

image.png

とりあえず実装できたみたい。

コードをきれいにします。(リファクタリング)

app.component.ts
export class AppComponent {
  title = 'app';
  numtest = Numtest(1);
  };

  //数字を文字列に変換する関数
  let Numtest = (i:number): string =>{
    return i.toString();
  };

今回はファンクションをシンプルにアロー関数でかきました。
ここでは変数名とかコメントの整理も含みます。

テストが通ることを確認。

 image.png

以上で一つのサイクルとなります。
似たサイクルの繰り返しでテストに慣れてきたら、
テストのテストは省略してもいいみたいです。
テストコードを書くということに慣れていないので、すごく時間がかかりました。
ごりごり実装派の私には苦手ですが、テストの自動化ができるので便利だなとも思います。

とりあえずここまで。

参考

参考にした本