手动注入路由器后单元测试注入器 (APP_INITIALIZER)

Unit-testing Injector after manually injecting Router (APP_INITIALIZER)

app.module.ts 中,我有以下内容:

{provide: APP_INITIALIZER, useFactory: appServiceFactory, multi: true, deps: [AppService]}

我试图在 AppService 中添加 Router 依赖项,但出现以下错误:

Cannot instantiate cyclic dependency! ApplicationRef...

我将 Injector 添加到我的 AppService 构造函数中,并手动添加 Router:

private get router() {
    return this.injector.get(Router);
}

我这样成功使用了:

this.router.navigate([ routePath ], {queryParams: {type: paramType}})
    .then(() => {
        return resolve();
    });

===

为了测试,我将 Injector 添加到提供程序,并且还添加了 Router:

let injector: Injector;

const routerStub = {navigate: jasmine.createSpy('navigate')};

beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [],
        providers: [
            AppService,
            ...,
            Injector,
            {provide: Router, useValue: routerStub}
        ]
    });

    injector = TestBed.get(Injector);

    spyOn(injector, 'get').and.returnValue(routerStub);
});

我收到以下错误:

ERROR LOG: 'Unhandled Promise rejection:', 'Cannot read property 'then' of undefined', '; Zone:', 'ProxyZone', '; Task:', 'jasmine.onComplete', '; Value:', TypeError: Cannot read property 'then' of undefined
TypeError: Cannot read property 'then' of undefined

我尝试将提供程序中的 Router 替换为导入中的 RouterTestingModule,但仍然出现相同的错误。

有什么想法吗?

谢谢!

===

编辑:已添加 routerStub

编辑 2:分辨率

感谢@Inge Olaisen 的帮助,我得以解决错误。答案:

1 - 使用 useClass(w/promise)而不是 useValue

的存根路由器
class MockRouter {
    navigate(routePath: any[], params: any) {
        return new Promise<boolean>(resolve => resolve(true));
    }
}

...

{provide: Router, useClass: MockRouter}

...

injector = TestBed.get(Injector);

spyOn(injector, 'get').and.returnValue(routerStub); // Not needed anymore

2 - 使用 RouterTestingModule

let injector: Injector;
let router: Router;

beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [
            RouterTestingModule
        ],
        providers: [
            AppService,
            ...,
            Injector,
            {provide: Router, useValue: routerStub}
        ]
    });

    injector = TestBed.get(Injector);
    router = TestBed.get(Router);

    spyOn(router, 'navigate').and.returnValue(new Promise<boolean>(resolve => resolve(true)))
});

嗯,你没有提供任何关于你的 routerstub 的信息,或者它是如何设置的,但你需要做的是模拟 return 值作为一个承诺。因为它期望得到一个,但是什么也没有得到,所以它是未定义的。

换句话说,.navigate 不 return this.router。

你可以试试:

class MockRoute {
navigate(routePath: any[], params: any) {
return new Promise();
}}

完全免责声明,我不习惯创建承诺,我习惯了可观察的方式,所以你可能需要正确地模拟新的承诺部分。

不过,我确实建议您使用 TypeMoq。那么你只需使用: const 路由器 = TypeMock.Mock.ofType(); router.setup(r => r.navigate).returns(()=> new Promise());

然后你使用 router.object 而不是 routerStub,但它会是: { provide: Router, useFactory: ()=> router.object } 代替 {provide: Router, useValue: routerStub}