Angular 9 ユニットテスト調査

##Learning Objectives
- Jasmine test framework とは何ですか？(ジャスミン)
- Jasmine でテストを書くには？
- Karma test runner とは何ですか？
- Angular CLIを使用してテストを作成して実行するにはどうすればよいですか？


###ジャスミン ＆　Karma
デフォルトでJasmineが組み込まれているので、実行自体も簡単です。
Jasmineというテストフレームワークを用いて記述したテストケースを
Karmaというタスクランナーでコードが書き換わるたびに実行するようにします。


###テストを走らせてみる

ユニットテストに必要なモジュール等は全てインストールしてくれます。 以下のコマンドでデフォルトのテストを走らせてみましょう。


```angular:terminal
ng test
```

テストファイルない場合！（スペックインストール）

```angular:terminal
npm install -g angular-spec-generator
```

スペックファイルビルド
必要なコンポーネントにスペックファイル作る

```angular:terminal
angular-spec-generator '/Users/user/Documents/angularwebapp/src/app/auth'
```

それで、****.spec.tsファイルが作られる。

1.**describe**（string、function）関数は、個々のテスト仕様の集合であるテストスイートと呼ばれるものを定義します。
2.**it**（string、function）関数は個々のTest Specを定義します。これは1つ以上のTest Expectationsを含みます。
3.**expect**（実際の）式は、Expectationと呼ばれるものです。 Matcherと組み合わせることで、アプリケーションで予想される動作が記述されます。
4.**matcher**（expected）式はMatcherと呼ばれるものです。 これは、渡された期待値と期待値関数とに渡された実際の値との論理比較を行い、偽の場合にはその仕様が失敗します。

##Setup and teardown

場合によっては、設定を行う必要があるフィーチャをテストするために、テストオブジェクトを作成することがあります。 また、テストが終了した後で、いくつかのファイルを削除する必要があるかもしれません。
これらのアクティビティはセットアップとティアダウン（クリーンアップ）と呼ばれ、ジャスミンにはこれを簡単にするために使用できるいくつかの機能があります。

**beforeAll** この関数は、記述されたテストスイート内のすべての仕様が実行される前に、一度呼び出されます。

**afterAll** この関数は、テストスイート内のすべての仕様が完了した後に一度呼び出されます。

**beforeEach** この関数は、実行された各テスト仕様が機能する前に呼び出されます。

**afterEach** この関数は、各テスト仕様が実行された後に呼び出されます。

これらの関数は次のように使用できます。

サンプル

```angular:.spec.ts
describe('Hello world', () => {

  let expected = "";

  beforeEach(() => {
    expected = "Hello World";
  });

  afterEach(() => {
    expected = "";
  });

  it('says hello', () => {
    expect(helloWorld())
        .toEqual(expected);
  });
});
```


サンプル 2

```angular:app.component.ts
export class AppComponent {
  title = 'app';
  greetings = 'Hello World!';
}
```

```angular:app.component.spec.ts
it('greetings は”Hello World!”であること', async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const app = fixture.debugElement.componentInstance;
    expect(app.greetings).toEqual('Hello World!');
  }));
}
```
The basic NgModule

```angular:app.component.ts
// imports
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

// @NgModule decorator with its metadata
@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
}
```

https://angular.io/guide/testing

エラー spec 1 failure 1
NodeDetailosComponent > greetings test
Error: Unspected value 'injectionToken' imported by the module 'DynamicTestModule'. please add an @NgModule annotaion.

Fix: {provide:USE_DEFAULT_LANG},

```angular:app.component.ts
beforeEach(async(() => {
 TestBed.configureTestingModule({
  imports:[HttpClientModule],
  providers:[
   {provide:USE_DEFAULT_LANG},
   TranslateService,
   TranslateStore,
   TranslateLoader,
   TranslateComplier,
   TranslateParser,
   MissingTranslationHandler,
 ],
   declarations:[NodeDetailOsComponent],
   }).compileComponents();
}));
```

エラー２
Error:Token InjectionToken USE_DEFAULT_LANG is missing a eprov definition.

##フォームテスト(HTML H1 tag テスト)

サンプル１

```
  it('should have an h1 tag of `Alert Button`', () => {
    expect(de.query(By.css('h1')).nativeElement.innerText).toBe('Alert Button');
  });
```

サンプル２

```angular:main.component.ts
<h1 class="header">悲観的な天気予報</h1>

<mat-tab-group mat-align-tabs="center">
  <mat-tab label="通常">
    <div class="container mat-elevation-z8">
      <table mat-table [dataSource]="dataSource">
        <ng-container matColumnDef="time">
..........
```

```angular:main.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { MainComponent } from './main.component';

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from 'src/app/module/material.module';
import { PipeModule } from 'src/app/module/pipe.module';
import { SharedModule } from 'src/app/module/shared.module';

describe('MainComponent', () => {
  let component: MainComponent;
  let fixture: ComponentFixture<MainComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        MainComponent
      ],
      imports: [
        BrowserAnimationsModule,
        MaterialModule,
        PipeModule,
        SharedModule,
      ],
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MainComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should render title in a h1 tag', () => {
    fixture = TestBed.createComponent(MainComponent);
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('h1').textContent).toContain('悲観的な天気予報');
  });

});
```

##component content テスト

```
it('should have message with 'warn'',()=> {
  expect(component.content).toBe('warn');
})
```

##component hide content テスト

```
it('should touggle the message boolean',() => {
  expect(component.hideContent).toBeTruthy();
  component.toggle();
  expect(component.hideContetnt).toBeFalsy();
})
```

```
  it('should have a message with `warn`', () => {
    expect(component.message).toMatch(/string$/);
  });
```

jasmine docs https://jasmine.github.io/tutorials/your_first_suite

```
describe('Adder', () => {
  // A jasmine spec
  it('should be able to add two whole numbers', () => {
    expect(Adder.add(2, 2)).toEqual(4);
  });

  it('should be able to add a whole number and a negative number', () => {
    expect(Adder.add(2, -1)).toEqual(1);
  });

  it('should be able to add a whole number and a zero', () => {
    expect(Adder.add(2, 0)).toEqual(2);
  });
});
```

###Testing Angular Service

```
it('should be created', inject([TestService], (service: TestService) => {
  expect(service).toBeTruthy();
}));
```

```
import { TestBed } from '@angular/core/testing';
import { UsersService } from './users.service';

describe('UsersService', () => {
  let usersService: UsersService; // Add this

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [UsersService]
    });

    usersService = TestBed.get(UsersService); // Add this
  });

  it('should be created', () => { // Remove inject()
    expect(usersService).toBeTruthy();
  });
});
```

https://scotch.io/tutorials/testing-angular-with-jasmine-and-karma-part-1