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