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

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

##環境
- Windows10
- Angular 5.2
- Angular-cli 1.6.5

#Angularを使ったテスト

##テストの種類

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

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

　![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/2ba1488d-8c29-135b-19bd-f2d6011b85f0.png)

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

 ![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/9426e115-db94-00f9-d808-87798198dd6b.png)

##テストコードかいてみる

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

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

```

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

toEqualはアサーションメソッドとよばれ、toEqualの他にもいっぱい[あります](https://www.buildinsider.net/web/angularjstips/0069)。

##テスト実行
```npm test```コマンド実行でできます。

テストが成功するとこちらの画像がでます。
　![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/b290836c-8b76-cb38-fec9-4751e4675b5f.png)


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

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

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

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

```

　![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/3213f1cf-1ee5-3874-3906-b07bd951f5d2.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. プリントする

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

##数字を文字列に変換

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

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

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

　![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/06ad5878-b9b4-5daf-17c5-142d946f50e3.png)

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

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

function Numtest(i: number): string {
    return '1';
  }
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/d473c719-998b-bb83-5a88-7456a6aa6b2c.png)

実装します。

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

function Numtest(i: number): string {
    return i.toString();
  }
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/6bb21776-6469-9d7a-df16-e0d7ec8aa4ed.png)

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

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

```typescript:app.component.ts
export class AppComponent {
  title = 'app';
  numtest = Numtest(1);
  };
  
  //数字を文字列に変換する関数
  let Numtest = (i:number): string =>{
    return i.toString();
  };
```

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

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

　![image.png](https://qiita-image-store.s3.amazonaws.com/0/201826/bdb69d9e-82f8-204c-e154-98e68ba6b174.png)


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

とりあえずここまで。

#参考
- [AngularJSアプリの単体テストを実施するには？（実行編）](https://www.buildinsider.net/web/angularjstips/0069)
- [50 分でわかるテスト駆動開発](https://channel9.msdn.com/Events/de-code/2017/DO03)
- [［動画で解説］和田卓人の“テスト駆動開発”講座](http://gihyo.jp/dev/serial/01/tdd)

##参考にした本
- [Angular アプリケーションプログラミング](https://www.amazon.co.jp/Angular%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E5%B1%B1%E7%94%B0-%E7%A5%A5%E5%AF%9B/dp/4774191302)