离子 2 ViewController 单元测试

Ionic 2 ViewController unit testing

我得到了以下单元测试来测试我用 Ionic 2 编写的组件。单元测试给出了一个 Ionic 库的错误,我假设我没有正确地模拟它或因此

import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils }               from '../../test';
import {} from 'jasmine';

import { LocationSearchModal } from './LocationSearchModal';
import { LocationService } from '../../services/LocationService';
import { PouchDbService } from '../../services/common/PouchDbService';

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TestBed } from '@angular/core/testing';
import { App, MenuController, NavController, Platform, Config, Keyboard, Form, IonicModule, ViewController, GestureController, NavParams }  from 'ionic-angular';
import { ConfigMock } from '../../mocks';
import { TranslateModule } from 'ng2-translate';
import { LoadingController } from 'ionic-angular';

let fixture: ComponentFixture<LocationSearchModal> = null;
let instance: any = null;

describe('LocationSearchModal', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        LocationSearchModal
      ],
      providers: [
        App, Platform, Form, Keyboard, MenuController, NavController, GestureController, LocationService, LoadingController,
        { provide: ViewController, useClass: class { ViewController = jasmine.createSpy("viewController"); } },
        { provide: NavParams, useClass: class { NavParams = jasmine.createSpy("navParams"); } },
        { provide: PouchDbService, useClass: class { PouchDbService = jasmine.createSpy("pouchDbService"); } },
        {provide: Config, useClass: ConfigMock}
      ],
      imports: [
        FormsModule,
        IonicModule,
        ReactiveFormsModule,
        TranslateModule.forRoot(),
      ],
    })
    .compileComponents()
    .then(() => {
      fixture = TestBed.createComponent(LocationSearchModal);
      instance = fixture.debugElement.componentInstance;
      fixture.autoDetectChanges(true);
    });
  }));

  afterEach(() => {
    fixture.destroy();
  });

  it('loads', () => {
    expect(fixture).not.toBeNull();
    expect(instance).not.toBeNull();
  })
})

这是相关摘录,它使用了正在测试的组件中的 ViewController。

this.locationService.getLocationById(this.selectedLocation)
      .subscribe((location: any) => {
        this.viewController.dismiss(location.doc)
      });

测试失败,我得到以下堆栈跟踪

  Chrome 53.0.2785 (Linux 0.0.0)
TypeError: viewCtrl._setHeader is not a function
    at new Header (webpack:///home/milinda/workspaces/eclipse/inspection/addedinspection/Inspection-Upgrade/~/ionic-angular/components/toolbar/toolbar.js:14:0 <- src/test.ts:11833:30)
    at new Wrapper_Header (/IonicModule/Header/wrapper.ngfactory.js:7:18)

这与我为

创建茉莉花间谍的 ViewController 行有关

{ provide: ViewController, useClass: class { ViewController = jasmine.createSpy("viewController"); } },

查看代码库后,我在此处找到了 _setHeader 方法

https://github.com/driftyco/ionic/blob/6b3e2ed447340cdd35c328c96aa7cfa5f34eb214/src/navigation/view-controller.ts#L364

我也尝试编写自定义提供程序,但也遇到了同样的错误。关于测试 ViewController.

的正确方法的任何想法

此外,有时在解决 ViewController 问题后,NavParams 可能会出现问题

我在单元测试中引用 ViewController 时遇到了同样的问题。我刚刚解决了它。 像这样创建一个模拟

class ViewControllerMock {
  public _setHeader(): any {
    return {}
  };
  public _setIONContent(): any {
    return {}
  };
  public _setIONContentRef(): any {
    return {}
  };
}

然后在对 TestBed.configureTestingModule 的调用中将其添加到您的提供商中,如下所示:

TestBed.configureTestingModule({
  declarations: [
    ...components,
    OrdinalPipe,
    IgnoreNulls
  ],
  providers: [
    NavController,
    ChartsService, FundsService, Utils, BlogService
    , Payment, PlanHelper, Storage, PalIdle, SimpleExpiry, ContentService, PlansService,
    App, Platform, Form, Keyboard, MenuController,
    { provide: ModalController, useClass: ModalControllerMock },
    { provide: ViewController, useClass: ViewControllerMock },
    { provide: Config, useClass: ConfigMock }
  ],
  imports: [
    FormsModule,
    IonicModule,
    ReactiveFormsModule,
  ],
})

当我今天早些时候遇到 viewCtrl._setHeader 不是函数错误时,这对我有用。希望对你有帮助。

基于 Marky Sparky 的回答。从离子 3+ 开始:

export class ViewControllerMock{
  readReady = {
    subscribe(){

    }
  };
  writeReady = {
    subscribe(){

    }
  };

  dismiss(){
    console.log('View Controller Dismiss Called');
  }
  _setHeader(){

  }
  _setNavbar(){

  }
  _setIONContent(){

  }
  _setIONContentRef(){

  }
}

正在处理版本:

Cordova CLI: 6.5.0 
Ionic Framework Version: 3.0.1
Ionic CLI Version: 3.0.0-beta7
ios-deploy version: 1.9.1 
ios-sim version: Not installed
OS: macOS Sierra
Node Version: v7.8.0
Xcode version: Xcode 8.3.2 Build version 8E2002

接受的答案不适用于 ionic 版本 3.9.2,但以下问题已解决:

export class ViewControllerMock {

  public readReady: any = {
    emit(): void {

    },
    subscribe(): any {

    }
  };

  public writeReady: any = {
    emit(): void {

    },
    subscribe(): any {

    }
  };

  public contentRef(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public didEnter(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public didLeave(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public onDidDismiss(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public onWillDismiss(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public willEnter(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public willLeave(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public willUnload(): any {
    return new Promise(function (resolve: Function): void {
      resolve();
    });
  }

  public dismiss(): any {
    return true;
  }

  public enableBack(): any {
    return true;
  }

  public getContent(): any {
    return true;
  }

  public hasNavbar(): any {
    return true;
  }

  public index(): any {
    return true;
  }

  public isFirst(): any {
    return true;
  }

  public isLast(): any {
    return true;
  }

  public pageRef(): any {
    return true;
  }

  public setBackButtonText(): any {
    return true;
  }

  public showBackButton(): any {
    return true;
  }

  public _setHeader(): any {
    return true;
  }

  public _setIONContent(): any {
    return true;
  }

  public _setIONContentRef(): any {
    return true;
  }

  public _setNavbar(): any {
    return true;
  }

  public _setContent(): any {
    return true;
  }

  public _setContentRef(): any {
    return true;
  }

  public _setFooter(): any {
    return true;
  }

}

Ionic Info

cli packages: 

    @ionic/cli-plugin-proxy : 1.5.6
    @ionic/cli-utils        : 1.14.0
    ionic (Ionic CLI)       : 3.14.0

local packages:

    @ionic/app-scripts : 3.1.0
    Ionic Framework    : ionic-angular 3.9.2

1. 创建 ViewController.

的 Jasmine 间谍
let viewCtrlSpy = jasmine.createSpyObj('ViewController', 
                          ['data', 'readReady', 'writeReady', 'dismiss', '_setHeader', '_setNavbar', '_setIONContent', '_setIONContentRef']);

2。在 providers 数组中使用 viewCtrlSpy spy 如下:

providers: [
.......
          {
            provide: ViewController,
            useValue: viewCtrlSpy
          }
..........

在这种情况下,间谍比模拟更有效。

如果有人没有注意到对 James Macmillan 的回答的评论:

@eesdil 写道:

From beenotung, there is built in mocks in ionic also: import {mockApp, mockConfig, mockPlatform, mockView} from "ionic-angular/util/mock-providers"; and use it like {provide: ViewController, useValue: mockView()}, – Sep 26 '17 at 9:40


这是对我有用的解决方案。

添加

{ provide: ViewController, useClass: class { ViewController = jasmine.createSpy("viewController"); } },

提供