Angular 7 使用继承和全局注入器进行测试
Angular 7 testing with inheritance and global injector
我在 Angular 7 开始一个新项目,并且有一个基础组件来集中我的一些全局变量和服务。由于项目可能会变得很大,我选择这种方法是为了避免在每个组件的开头以及 super() 调用时进行大量导入。
为此,我实施了 here, where an external class stores a dependency injector to be used in the base component. As discussed 中描述的方法,必须进行修改以符合 Angular 7(注入器必须在 AppModule 中初始化)。 (见下面的 plunker)
这对 运行 项目很好用,当我尝试 运行 单元测试(使用 karma-jasmine)时问题就来了。由于 AppInjector 是在模块中初始化的,所以测试 运行 没有初始化它。然后,由于我的基本组件试图调用注入器的函数,所以它中断了。
如果有人对此有任何解决方案,通过修改测试结构或 AppInjector 本身,将不胜感激。
这是一个包含所有相关代码的插件。该示例是使用 primeng toast 模块的全局通知组件和基本组件中的全局通知服务。 (我无法让 plunker 正常工作,某种 MIME 类型错误,但代码就在那里)
https://next.plnkr.co/edit/7v5nB8cORWsnpPAL?preview
当我 运行 ng 测试时,这是我得到的错误:
Chrome 71.0.3578 (Windows 10.0.0) AppComponent should create the app FAILED
TypeError: Cannot read property 'get' of undefined
at NotificationsComponent.BaseComponent (http://localhost:9876/src/app/components/base.component.ts?:22:50)
at new NotificationsComponent (http://localhost:9876/src/app/components/utils/notifications/notifications.component.ts?:17:13)
at createClass (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:20716:1)
at createDirectiveInstance (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:20595:1)
at createViewNodes (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:21821:1)
at callViewAction (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:22137:1)
at execComponentViewsAction (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:22056:1)
at createViewNodes (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:21849:1)
at createRootView (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:21735:1)
at callWithDebugContext (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:22767:1)
Error: Uncaught (in promise): TypeError: Cannot read property 'get' of undefined
at resolvePromise (http://localhost:9876/node_modules/zone.js/dist/zone.js?:831:1)
at http://localhost:9876/node_modules/zone.js/dist/zone.js?:896:1
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:9876/node_modules/zone.js/dist/zone.js?:423:1)
at AsyncTestZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.AsyncTestZoneSpec.onInvokeTask (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:698:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvokeTask (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:317:1)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:9876/node_modules/zone.js/dist/zone.js?:422:1)
at Zone../node_modules/zone.js/dist/zone.js.Zone.runTask (http://localhost:9876/node_modules/zone.js/dist/zone.js?:195:1)
at drainMicroTaskQueue (http://localhost:9876/node_modules/zone.js/dist/zone.js?:601:1)
Expected undefined to be truthy.
at UserContext.<anonymous> (http://localhost:9876/src/app/app.component.spec.ts?:35:21)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/node_modules/zone.js/dist/zone.js?:391:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:289:1)
在测试中,您可以从 TestBed
获得注射器。因此,您可以像所有其他事情一样在 beforeEach
中初始化 AppInjector
。只需在 createComponent
调用之前执行此操作即可。
这是您的 Plunker 示例中更改后的代码:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
ToastModule
],
declarations: [
AppComponent,
NotificationsComponent
]
}).compileComponents().then(() => {
AppInjector.setInjector(TestBed.get(Injector));
fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
});
}));
我在 Angular 7 开始一个新项目,并且有一个基础组件来集中我的一些全局变量和服务。由于项目可能会变得很大,我选择这种方法是为了避免在每个组件的开头以及 super() 调用时进行大量导入。
为此,我实施了 here, where an external class stores a dependency injector to be used in the base component. As discussed
这对 运行 项目很好用,当我尝试 运行 单元测试(使用 karma-jasmine)时问题就来了。由于 AppInjector 是在模块中初始化的,所以测试 运行 没有初始化它。然后,由于我的基本组件试图调用注入器的函数,所以它中断了。
如果有人对此有任何解决方案,通过修改测试结构或 AppInjector 本身,将不胜感激。
这是一个包含所有相关代码的插件。该示例是使用 primeng toast 模块的全局通知组件和基本组件中的全局通知服务。 (我无法让 plunker 正常工作,某种 MIME 类型错误,但代码就在那里)
https://next.plnkr.co/edit/7v5nB8cORWsnpPAL?preview
当我 运行 ng 测试时,这是我得到的错误:
Chrome 71.0.3578 (Windows 10.0.0) AppComponent should create the app FAILED
TypeError: Cannot read property 'get' of undefined
at NotificationsComponent.BaseComponent (http://localhost:9876/src/app/components/base.component.ts?:22:50)
at new NotificationsComponent (http://localhost:9876/src/app/components/utils/notifications/notifications.component.ts?:17:13)
at createClass (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:20716:1)
at createDirectiveInstance (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:20595:1)
at createViewNodes (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:21821:1)
at callViewAction (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:22137:1)
at execComponentViewsAction (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:22056:1)
at createViewNodes (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:21849:1)
at createRootView (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:21735:1)
at callWithDebugContext (http://localhost:9876/node_modules/@angular/core/fesm5/core.js?:22767:1)
Error: Uncaught (in promise): TypeError: Cannot read property 'get' of undefined
at resolvePromise (http://localhost:9876/node_modules/zone.js/dist/zone.js?:831:1)
at http://localhost:9876/node_modules/zone.js/dist/zone.js?:896:1
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:9876/node_modules/zone.js/dist/zone.js?:423:1)
at AsyncTestZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.AsyncTestZoneSpec.onInvokeTask (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:698:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvokeTask (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:317:1)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (http://localhost:9876/node_modules/zone.js/dist/zone.js?:422:1)
at Zone../node_modules/zone.js/dist/zone.js.Zone.runTask (http://localhost:9876/node_modules/zone.js/dist/zone.js?:195:1)
at drainMicroTaskQueue (http://localhost:9876/node_modules/zone.js/dist/zone.js?:601:1)
Expected undefined to be truthy.
at UserContext.<anonymous> (http://localhost:9876/src/app/app.component.spec.ts?:35:21)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (http://localhost:9876/node_modules/zone.js/dist/zone.js?:391:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke (http://localhost:9876/node_modules/zone.js/dist/zone-testing.js?:289:1)
在测试中,您可以从 TestBed
获得注射器。因此,您可以像所有其他事情一样在 beforeEach
中初始化 AppInjector
。只需在 createComponent
调用之前执行此操作即可。
这是您的 Plunker 示例中更改后的代码:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
ToastModule
],
declarations: [
AppComponent,
NotificationsComponent
]
}).compileComponents().then(() => {
AppInjector.setInjector(TestBed.get(Injector));
fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
});
}));