测试套件在ionic 2
中仍未准备就绪。所以我正在使用本教程进行测试。这本质上使用angular 2
测试套件。这是我的test.ts
declare var __karma__: any;
declare var require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function (): void { /* no op */};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
);
// Then we find all the tests.
const context: any = require.context('./', true, /.spec.ts/);
// And load the modules.
context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();
export class TestUtils {
public static beforeEachCompiler(components: Array<any>): Promise<{fixture: any, instance: any}> {
return TestUtils.configureIonicTestingModule(components)
.compileComponents().then(() => {
let fixture: any = TestBed.createComponent(components[0]);
return {
fixture: fixture,
instance: fixture.debugElement.componentInstance,
};
});
}
public static configureIonicTestingModule(components: Array<any>): typeof TestBed {
return TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [
...components
],
providers: [
NavController,LoadingController,App, Form, Keyboard, DomController, MenuController,
{ provide: Bookemon, useClass: BookMock},
{ provide: Authentication, useClass: AuthMock},
{provide: Storage, useClass: StorageMock},
{provide: Config, useClass: ConfigMock},
{provide: Platform, useClass: PlatformMock},
{provide: Events, useClass: Eventsmock}
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
SwingModule
],
});
}
我正在尝试测试我的tab.ts
组件。
tab.ts
@Component({
selector: 'page-tabs',
templateUrl: 'tabs.html'
})
export class TabsPage {
user: any;
tab1Root: any = UserHuntsPage;
tab2Root: any = HomePage;
tab3Root: any = FeedPage;
constructor(public navCtrl: NavController , public auth: Authentication ,public events: Events) {
}
ngOnInit(){
this.events.subscribe('logout-user' , () => {
this.navCtrl.setRoot(WelcomePage);
})
}
}
这是tab.pec.ts
let fixture: ComponentFixture<TabsPage> = null;
let instance: any = null;
describe('Tabs component',()=>{
beforeEach(async(() => TestUtils.beforeEachCompiler([TabsPage]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
})));
it('initialises', () => {
expect(1).toBeTruthy();
});
})
当我运行测试时,我收到此错误,
Error: No provider for DeepLinker!
at NoProviderError.BaseError [as constructor] (webpack:///~/@angular/core/src/facade/errors.js:24:0 <- src/test.ts:8542:34)
at NoProviderError.AbstractProviderError [as constructor] (webpack:///~/@angular/core/src/di/reflective_errors.js:41:0 <- src/test.ts:72995:16)
at new NoProviderError (webpack:///~/@angular/core/src/di/reflective_errors.js:72:0 <- src/test.ts:73026:16)
at ReflectiveInjector_._throwOrNull (webpack:///~/@angular/core/src/di/reflective_injector.js:758:0 <- src/test.ts:119137:19)
at ReflectiveInjector_._getByKeyDefault (webpack:///~/@angular/core/src/di/reflective_injector.js:786:0 <- src/test.ts:119165:25)
at ReflectiveInjector_._getByKey (webpack:///~/@angular/core/src/di/reflective_injector.js:749:0 <- src/test.ts:119128:25)
at ReflectiveInjector_.get (webpack:///~/@angular/core/src/di/reflective_injector.js:558:0 <- src/test.ts:118937:21)
at TestBed.get (webpack:///~/@angular/core/bundles/core-testing.umd.js:814:0 <- src/test.ts:39277:67)
at CompiledTemplate.proxyViewClass.AppView.injectorGet (webpack:///~/@angular/core/src/linker/view.js:109:0 <- src/test.ts:119679:45)
at CompiledTemplate.proxyViewClass.DebugAppView.injectorGet (webpack:///~/@angular/core/src/linker/view.js:351:0 <- src/test.ts:119921:49)
Error: Uncaught (in promise): Error: Error in ./TabsPage class TabsPage - inline template:0:0 caused by: No provider for DeepLinker!
at resolvePromise (webpack:///~/zone.js/dist/zone.js:468:0 <- src/test.ts:141307:31)
at resolvePromise (webpack:///~/zone.js/dist/zone.js:453:0 <- src/test.ts:141292:17)
at webpack:///~/zone.js/dist/zone.js:502:0 <- src/test.ts:141341:17
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:265:0 <- src/test.ts:141104:35)
at ProxyZoneSpec.onInvokeTask (webpack:///~/zone.js/dist/proxy.js:103:0 <- src/test.ts:110667:39)
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:264:0 <- src/test.ts:141103:40)
at Zone.runTask (webpack:///~/zone.js/dist/zone.js:154:0 <- src/test.ts:140993:47)
at drainMicroTaskQueue (webpack:///~/zone.js/dist/zone.js:401:0 <- src/test.ts:141240:35)
我没有在我的应用程序中的任何地方使用过DeepLinker
。我认为这可能是我的提供者中某些东西的依赖关系。我花了很多时间在这上面,我不明白为什么会发生这种情况。任何帮助将不胜感激。
编辑
我在providers
中添加了DeepLinker
,但这给出了另一个错误,
Failed: Can't resolve all parameters for DeepLinker: (?, ?, ?).
Error: Can't resolve all parameters for DeepLinker: (?, ?, ?).
at CompileMetadataResolver._getDependenciesMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:623:0 <- src/test.ts:50686:19)
at CompileMetadataResolver._getTypeMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:517:0 <- src/test.ts:50580:26)
at webpack:///~/@angular/compiler/src/metadata_resolver.js:667:0 <- src/test.ts:50730:41
at Array.forEach (native)
at CompileMetadataResolver._getProvidersMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:647:0 <- src/test.ts:50710:19)
at CompileMetadataResolver._loadNgModuleMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:430:0 <- src/test.ts:50493:50)
at CompileMetadataResolver.loadNgModuleMetadata (webpack:///~/@angular/compiler/src/metadata_resolver.js:313:0 <- src/test.ts:50376:29)
at RuntimeCompiler._loadModules (webpack:///~/@angular/compiler/src/runtime_compiler.js:99:0 <- src/test.ts:69258:41)
at RuntimeCompiler._compileModuleAndAllComponents (webpack:///~/@angular/compiler/src/runtime_compiler.js:83:0 <- src/test.ts:69242:35)
at RuntimeCompiler.compileModuleAndAllComponentsAsync (webpack:///~/@angular/compiler/src/runtime_compiler.js:65:0 <- src/test.ts:69224:21)
编辑
将提供程序添加为{ provide: DeepLinker, useValue: {} }
会导致新的错误,
TypeError: this.parent.registerChildNav is not a function
at new Tabs (webpack:///~/ionic-angular/components/tabs/tabs.js:173:0 <- src/test.ts:46470:25)
at new Wrapper_Tabs (/IonicModule/Tabs/wrapper.ngfactory.js:7:18)
at CompiledTemplate.proxyViewClass.View_TabsPage0.createInternal (/DynamicTestModule/TabsPage/component.ngfactory.js:27:20)
at CompiledTemplate.proxyViewClass.AppView.create (webpack:///~/@angular/core/src/linker/view.js:74:0 <- src/test.ts:119644:21)
at CompiledTemplate.proxyViewClass.DebugAppView.create (webpack:///~/@angular/core/src/linker/view.js:330:0 <- src/test.ts:119900:44)
at CompiledTemplate.proxyViewClass.View_TabsPage_Host0.createInternal (/DynamicTestModule/TabsPage/host.ngfactory.js:16:19)
at CompiledTemplate.proxyViewClass.AppView.createHostView (webpack:///~/@angular/core/src/linker/view.js:81:0 <- src/test.ts:119651:21)
at CompiledTemplate.proxyViewClass.DebugAppView.createHostView (webpack:///~/@angular/core/src/linker/view.js:341:0 <- src/test.ts:119911:52)
at ComponentFactory.create (webpack:///~/@angular/core/src/linker/component_factory.js:154:0 <- src/test.ts:54276:25)
at initComponent (webpack:///~/@angular/core/bundles/core-testing.umd.js:852:0 <- src/test.ts:39321:53)
Error: Uncaught (in promise): Error: Error in ./TabsPage class TabsPage - inline template:0:0 caused by: this.parent.registerChildNav is not a function
at resolvePromise (webpack:///~/zone.js/dist/zone.js:468:0 <- src/test.ts:141416:31)
at resolvePromise (webpack:///~/zone.js/dist/zone.js:453:0 <- src/test.ts:141401:17)
at webpack:///~/zone.js/dist/zone.js:502:0 <- src/test.ts:141450:17
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:265:0 <- src/test.ts:141213:35)
at ProxyZoneSpec.onInvokeTask (webpack:///~/zone.js/dist/proxy.js:103:0 <- src/test.ts:110667:39)
at ZoneDelegate.invokeTask (webpack:///~/zone.js/dist/zone.js:264:0 <- src/test.ts:141212:40)
at Zone.runTask (webpack:///~/zone.js/dist/zone.js:154:0 <- src/test.ts:141102:47)
at drainMicroTaskQueue (webpack:///~/zone.js/dist/zone.js:401:0 <- src/test.ts:141349:35)
我遇到了与使用离子标签启动器模板的 OP 相同的问题。通过将此处的建议与单元测试教程提供的 mocks.ts 中的示例相结合,我设法使单元测试正常工作。
首先,我通过在mocks.ts中添加一个模拟类来嘲笑DeepLinker:
export class DeepLinkerMock {
}
然后将其添加为test.ts中的TestBed.configureTestingModule中的提供程序:
{provide: DeepLinker, useClass: DeepLinkerMock},
您还需要为其添加导入,以及在test.ts中为NavMock添加导入:
import {ConfigMock, PlatformMock, NavMock, DeepLinkerMock} from './mocks';
此时,您的测试将失败,并显示 this.parent.registerChildNav 不是一个函数。我在ionic-ang(file nav-controller-base.js)中查找了registerChildNav方法的签名。您需要在 mocks.ts 的 NavMock 类中为此方法添加一个存根:
export class NavMock {
...
public registerChildNav(nav: any): void {
return ;
}
}
现在,您的测试将失败,并且没有过渡控制器的提供程序!这可以通过添加该提供程序轻松修复。此时,我的提供程序如下所示:
providers: [
App, Form, Keyboard, DomController, MenuController, GestureController, TransitionController,
{provide: Platform, useClass: PlatformMock},
{provide: Config, useClass: ConfigMock},
{provide: DeepLinker, useClass: DeepLinkerMock},
{provide: NavController, useClass: NavMock}],
请注意,我将 NavController 提供程序替换为模拟的提供程序 - 它存在于教程代码中,但没有被引用。仅供参考,GestureController 也不在原始教程代码中 - 选项卡启动器项目中的其他原始四个页面之一需要它。
不要忘记为转换控制器(和手势控制器)添加导入。我的编辑(Webstorm)提出了三个选择。我选择了这个 - 不确定它是否正确:
import {TransitionController} from "ionic-angular/transitions/transition-controller";
此时,我有四个基本形式的单元测试,这些测试在教程中建议用于选项卡启动器中的四个页面。这是tabs.spec.ts:
import {Component} from "@angular/core";
import {HomePage} from "../home/home";
import {AboutPage} from "../about/about";
import {ContactPage} from "../contact/contact";
@Component({
templateUrl: './tabs.html'
})
export class TabsPage {
// this tells the tabs component which Pages
// should be each tab's root Page
tab1Root: any = HomePage;
tab2Root: any = AboutPage;
tab3Root: any = ContactPage;
constructor() {
}
}
我想我会遵循这种模式,因为我继续使用更多没有被教程编写者模拟的框架部分。
你是对的,它可能是其中一个组件的依赖关系。您是否尝试过像这样将深度链接器提供给测试平台:
TestBed.configureTestingModule({
...
providers: [
DeepLinker,
... // the usual stuff
如果确实不需要它,您也可以轻松删除其中的功能:
TestBed.configureTestingModule({
...
providers: [
{ provide: DeepLinker, useValue: {} },
... // the usual stuff
编辑到最后一个错误:
以这种方式提供深度链接器成功地实例化并使用空对象覆盖了实际的深度链接器实现。但是,应用程序的某些部分需要缺少registerChildNav
方法。最好的办法是在覆盖原始 DeepLinker 实现的对象上创建此方法。
let deepLinkerStub = {
registerChildNav: () => {}
};
TestBed.configureTestingModule({
...
providers: [
{ provide: DeepLinker, useValue: deepLinkerStub },
... // the usual stuff
检查 DeepLenderer 的原始实现,了解原始 registerChildNav 的工作原理,并为此测试创建一个存根方法。
在test.ts
中更新提供程序
providers: [
{provide: DeepLinker, useClass: DeepLinkerMock},
{provide: NavController, useClass: NavMock}
...config.providers
],
以及更新 mock.ts 添加两个类DeepLinkerMock
&&NavMock
export class DeepLinkerMock{
}
export class NavMock {
public length(): number {
return 1; }
public push(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public getActive(): any {
return {
'instance': {
'model': 'something',
},
}; }
public setRoot(): any {
return true; }
public pop(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public registerChildNav(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public unregisterChildNav(): any {
return new Promise(function(resolve: Function): void {
resolve();
}); }
public popToRoot(): any {
return true; }
public canGoBack(): any {
return true; } }