简体   繁体   English

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

[英]How should I Unit test Angular2 components and modules that has imported other modules (and components)

I have spent a while getting the hang of modules in Angular2 and really like them but I am a little uncertain as to best approach for testing both my modules and the components within. 我花了一段时间来获取Angular2中的模块,并且非常喜欢它们,但我对于测试我的模块和组件内部的最佳方法有点不确定。 (I also realise that my app.component can and probably should be broken out more but for now it is helpful while learning the testing framework to be a little more complex) (我也意识到我的app.component可以并且可能应该更多地分解,但是现在它在学习测试框架时更有用了)

For example this is my app.module: 例如,这是我的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 {

}

and this is what my app.component looks like: 这就是我的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;
  }
}

So I know I can potentially mock out all the Components with for example the MaterialComponents (this is just a wrapper module for the material components) within my tests but this seems a little tedious. 所以我知道我可以在我的测试中模拟所有组件,例如MaterialComponents (这只是材料组件的包装模块),但这看起来有点单调乏味。 Is that my only options and if so does it make sense to make creating a mock of components when creating the components part of the process. 这是我唯一的选择,如果是这样,在创建流程的组件部分时创建组件的模拟是有意义的。

for informational purposes this is what my material module looks like and my views and components modules are similar: 为了提供信息,这是我的材料模块的样子,我的视图和组件模块是相似的:

import { NgModule } from '@angular/core';

// Material
import { MdCardModule } from '@angular2-material/card';
import { MdButtonModule } from '@angular2-material/button';
import { MdInputModule } from '@angular2-material/input';
import { MdToolbarModule } from '@angular2-material/toolbar';
import { MdListModule } from '@angular2-material/list';
import { MdIconModule, MdIconRegistry } from '@angular2-material/icon';



const MATERIAL_UI_MODULES = [
  MdCardModule,
  MdButtonModule,
  MdInputModule,
  MdToolbarModule,
  MdIconModule,
  MdListModule
]
const MATERIAL_UI_REGISTRIES = [
  MdIconRegistry
]

@NgModule({
  imports:[
    ...MATERIAL_UI_MODULES,
  ],
  providers: MATERIAL_UI_REGISTRIES,
  exports:[
    ...MATERIAL_UI_MODULES,
  ]
})
export class MaterialModule {

}

So I eventually figured out how to do this and this is my current solution: 所以我最终想出了如何做到这一点,这是我目前的解决方案:

/* 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)
    });

  })));
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM