【问题标题】:How should I Unit test Angular2 components and modules that has imported other modules (and components)我应该如何对已导入其他模块(和组件)的 Angular 2 组件和模块进行单元测试
【发布时间】:2016-10-05 12:54:42
【问题描述】:

我花了一段时间来了解 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;
  }
}

所以我知道我可以在我的测试中使用例如MaterialComponents(这只是材料组件的包装模块)来模拟所有组件,但这似乎有点乏味。这是我唯一的选择吗?如果是这样,在创建流程的组件部分时创建组件模拟是否有意义。

出于参考目的,这是我的材料模块的外观,我的视图和组件模块类似:

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 {

}

【问题讨论】:

    标签: unit-testing angular angular-material2


    【解决方案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)
        });
    
      })));
    });
    

    【讨论】:

      猜你喜欢
      • 2019-05-29
      • 1970-01-01
      • 2018-07-13
      • 2020-08-19
      • 2023-03-06
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2017-06-17
      相关资源
      最近更新 更多