Unit testing 我应该如何对导入了其他模块(和组件)的Angular2组件和模块进行单元测试

Unit testing 我应该如何对导入了其他模块(和组件)的Angular2组件和模块进行单元测试,unit-testing,angular,angular-material2,Unit Testing,Angular,Angular Material2,我花了一段时间了解Angular2中模块的诀窍,并且非常喜欢它们,但对于测试我的模块和其中的组件的最佳方法,我有点不确定。(我也意识到,我的app.component可以而且可能应该被更多地分解,但现在它在学习测试框架变得更复杂时是有帮助的) 例如,这是我的app.module: import { createStore, compose, applyMiddleware } from 'redux'; import ReduxThunk from 'redux-thunk'; import {

我花了一段时间了解Angular2中模块的诀窍,并且非常喜欢它们,但对于测试我的模块和其中的组件的最佳方法,我有点不确定。(我也意识到,我的app.component可以而且可能应该被更多地分解,但现在它在学习测试框架变得更复杂时是有帮助的)

例如,这是我的app.module:

import { createStore, compose, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import { AUTH_PROVIDERS } from 'angular2-jwt';

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { ComponentsModule } from './components';
import { MaterialModule} from './material';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { ViewsModule } from './+views';

import { rootReducer } from './dataStore';

import { CurrentUserModel } from './models/current-user'


const appStore = createStore(rootReducer, applyMiddleware(ReduxThunk));

const APP_DECLARATIONS = [
  AppComponent
];

const APP_PROVIDERS = [
  { provide: 'AppStore', useValue: appStore },
  CurrentUserModel
];

@NgModule({
  imports:[
    FormsModule,
    BrowserModule,
    RouterModule,// here as well as in our Views Module because of router-outlet
    ViewsModule,
    MaterialModule, // here as well as in our Views & componet Module because used in App componet
    ComponentsModule
  ],
  declarations: APP_DECLARATIONS,
  bootstrap:[AppComponent],
  providers: APP_PROVIDERS,
})
export class AppModule {

}
这就是我的app.component的外观:

import { Component, ViewChild, AfterViewInit } from '@angular/core';

import { Router } from '@angular/router';

@Component({
  selector: 'app',
  styleUrls:['app.component.scss'],
  template: `
  <md-toolbar>
  <!--  <i class="material-icons demo-toolbar-icon">menu</i> -->
    <span class="toolbar-brand">Franks</span>
    <span *ngIf="searchActive" role="search" class="fill-remaining-space">
        <span class="search-input-container flex flex-1">
          <i class="material-icons search-link">search</i>
          <input class="search-input" placeholder="Search" type="text" id="searchInput" #searchInput (keyup.esc)="exitSearch($event)"/>
        </span>
    </span>
    <i *ngIf="searchActive" class="material-icons right selectable" (click)="exitSearch($event)">close</i>

    <span *ngIf="!searchActive" class="fill-remaining-space">

    </span>
    <span *ngIf="!searchActive" role="navmenu">
      <span class="hlink" routerLink="/" routerLinkActive="active">home</span>
      <span class="hlink" routerLink="/profile" routerLinkActive="active">Profile</span>
      <span class="hlink" routerLink="/login" routerLinkActive="active">Login</span>
      <span class="hlink" routerLink="/signup" routerLinkActive="active">Sign Up</span>
      <i class="material-icons search-link" (click)="activeSearch($event)">search</i>
    </span>
  </md-toolbar>
  <div class="container">
    <router-outlet></router-outlet>
  </div>
  `,
})
export class AppComponent {
  @ViewChild('searchInput') searchInputRef;

  ngAfterViewChecked() {
    if(this.searchActive && this.searchInputRef){
      console.log(this.searchInputRef);       
      this.searchInputRef.nativeElement.focus();
    }
  }
  searchActive: boolean;
  constructor(public router: Router) {
    this.searchActive = false;
  }

  activeSearch(event):void {
    this.searchActive = true;
  }

  exitSearch(event) : void {
    this.searchActive = false;
  }
}

因此,我最终想出了如何做到这一点,这是我目前的解决方案:

/* tslint:disable:no-unused-variable */
import { TestBed, inject, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { By } from '@angular/platform-browser';

import { Component,ViewChild, AfterViewChecked  } from '@angular/core';
import { Router } from '@angular/router';
import { Location, CommonModule } from '@angular/common';
import { MaterialModule} from './material';

@Component({
  template: '<div></div>'
})
class DummyComponent {
}


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

describe('component: TestComponent', function () {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        CommonModule,
        RouterTestingModule.withRoutes([
         { path: 'profile', component: DummyComponent },
         { path: 'login', component: DummyComponent },
         { path: 'signup', component: DummyComponent },
         { path: '', component: DummyComponent }
       ]),
       MaterialModule
      ],
      declarations: [ AppComponent, DummyComponent ]
    });
  });

  it('should create the app', async(() => {
    let fixture = TestBed.createComponent(AppComponent);
    let app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));

  it('should be navigate to correct url for each option in navmenu',
    async(inject([Router, Location], (router: Router, location: Location) => {

    let fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();

    fixture.debugElement.query(By.css('span.hlink[routerLink="/profile"]')).nativeElement.click();
    fixture.whenStable().then(() => {
      expect(location.path()).toEqual('/profile');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/profile"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)

      fixture.debugElement.query(By.css('span.hlink[routerLink="/login"]')).nativeElement.click();
      return fixture.whenStable();
    }).then(() => {
      expect(location.path()).toEqual('/login');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/login"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)

      fixture.debugElement.query(By.css('span.hlink[routerLink="/signup"]')).nativeElement.click();
      return fixture.whenStable();
    }).then(() => {
      expect(location.path()).toEqual('/signup');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/signup"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)

      fixture.debugElement.query(By.css('span.hlink[routerLink="/"]')).nativeElement.click();
      return fixture.whenStable();
    }).then(() => {
      expect(location.path()).toEqual('/');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)
    });

  })));
});
/*tslint:disable:没有未使用的变量*/
从“@angular/core/testing”导入{TestBed,inject,async};
从“@angular/router/testing”导入{RouterTestingModule};
从“@angular/platform browser”导入{By}”;
从“@angular/core”导入{Component,ViewChild,AfterViewChecked};
从'@angular/Router'导入{Router};
从“@angular/common”导入{Location,CommonModule};
从“/material”导入{MaterialModule};
@组成部分({
模板:“”
})
类DummyComponent{
}
从“./app.component”导入{AppComponent};
描述('component:TestComponent',函数(){
在每个之前(()=>{
TestBed.configureTestingModule({
进口:[
公共模块,
RouterTestingModule.withRoutes([
{路径:'profile',组件:DummyComponent},
{路径:'login',组件:DummyComponent},
{路径:'signup',组件:DummyComponent},
{路径:“”,组件:DummyComponent}
]),
材料模块
],
声明:[AppComponent,DummyComponent]
});
});
它('应该创建应用',异步(()=>{
让fixture=TestBed.createComponent(AppComponent);
设app=fixture.debugElement.componentInstance;
expect(app.toBeTruthy();
}));
它('应该导航到导航菜单中每个选项的正确url',
异步(注入([路由器,位置],(路由器:路由器,位置)=>{
让fixture=TestBed.createComponent(AppComponent);
fixture.detectChanges();
fixture.debugElement.query(By.css('span.hlink[routerLink=“/profile”])).nativeElement.click();
fixture.whenStable()然后(()=>{
expect(location.path()).toEqual('/profile');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink=“/profile”])).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.queryselectoral('span.hlink.active').length)。toEqual(1)
fixture.debugElement.query(By.css('span.hlink[routerLink=“/login”])).nativeElement.click();
返回夹具。whenStable();
}).然后(()=>{
expect(location.path()).toEqual('/login');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink=“/login”])).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.queryselectoral('span.hlink.active').length)。toEqual(1)
fixture.debugElement.query(By.css('span.hlink[routerLink=“/signup”])).nativeElement.click();
返回夹具。whenStable();
}).然后(()=>{
expect(location.path()).toEqual('/signup');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink=“/signup”])).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.queryselectoral('span.hlink.active').length)。toEqual(1)
fixture.debugElement.query(By.css('span.hlink[routerLink=“/”])).nativeElement.click();
返回夹具。whenStable();
}).然后(()=>{
expect(location.path()).toEqual('/');
expect(fixture.debugElement.query(By.css('span.hlink[routerLink=“/”])).classes['active']).toBeTruthy();
expect(fixture.debugElement.nativeElement.queryselectoral('span.hlink.active').length)。toEqual(1)
});
})));
});
/* tslint:disable:no-unused-variable */
import { TestBed, inject, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { By } from '@angular/platform-browser';

import { Component,ViewChild, AfterViewChecked  } from '@angular/core';
import { Router } from '@angular/router';
import { Location, CommonModule } from '@angular/common';
import { MaterialModule} from './material';

@Component({
  template: '<div></div>'
})
class DummyComponent {
}


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

describe('component: TestComponent', function () {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        CommonModule,
        RouterTestingModule.withRoutes([
         { path: 'profile', component: DummyComponent },
         { path: 'login', component: DummyComponent },
         { path: 'signup', component: DummyComponent },
         { path: '', component: DummyComponent }
       ]),
       MaterialModule
      ],
      declarations: [ AppComponent, DummyComponent ]
    });
  });

  it('should create the app', async(() => {
    let fixture = TestBed.createComponent(AppComponent);
    let app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));

  it('should be navigate to correct url for each option in navmenu',
    async(inject([Router, Location], (router: Router, location: Location) => {

    let fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();

    fixture.debugElement.query(By.css('span.hlink[routerLink="/profile"]')).nativeElement.click();
    fixture.whenStable().then(() => {
      expect(location.path()).toEqual('/profile');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/profile"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)

      fixture.debugElement.query(By.css('span.hlink[routerLink="/login"]')).nativeElement.click();
      return fixture.whenStable();
    }).then(() => {
      expect(location.path()).toEqual('/login');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/login"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)

      fixture.debugElement.query(By.css('span.hlink[routerLink="/signup"]')).nativeElement.click();
      return fixture.whenStable();
    }).then(() => {
      expect(location.path()).toEqual('/signup');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/signup"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)

      fixture.debugElement.query(By.css('span.hlink[routerLink="/"]')).nativeElement.click();
      return fixture.whenStable();
    }).then(() => {
      expect(location.path()).toEqual('/');
      expect(fixture.debugElement.query(By.css('span.hlink[routerLink="/"]')).classes['active']).toBeTruthy();
      expect(fixture.debugElement.nativeElement.querySelectorAll('span.hlink.active').length).toEqual(1)
    });

  })));
});