【问题标题】:Angular 5 testing code in module constructor模块构造函数中的 Angular 5 测试代码
【发布时间】:2017-12-08 01:46:52
【问题描述】:

我正在尝试测试我的模块构造函数之一中的代码。基本上,模块(名为GraphqlModule)配置一个服务(名为Graphql)并提供它。配置发生在模块的构造函数中。

这是我用来测试模块的代码。

it('should use the GraphqlConfigs and ServerConfigs', (done: DoneFn) => {

    // Adding spies to Config classes
    let serverConfigs = new ServerConfigs();
    let serverDomainSpy = spyOnProperty(serverConfigs, 'ServerDomain', 'get').and.callThrough();
    let serverPortSpy = spyOnProperty(serverConfigs, 'ServerPort', 'get').and.callThrough();

    let gqlConfigs = new GraphqlConfigs();
    let protocolSpy = spyOnProperty(gqlConfigs, 'EndpointProtocol', 'get').and.callThrough();
    let endpointNameSpy = spyOnProperty(gqlConfigs, 'EndpointName', 'get').and.callThrough();

    TestBed.configureTestingModule({
        imports: [ GraphqlModule ],
        providers: [
            {provide: ServerConfigs, useValue: serverConfigs}, // Replacing real config classes with the ones spied on.
            {provide: GraphqlConfigs, useValue: gqlConfigs}
        ]

    }).compileComponents().then(() => {

        // This line seems to make Angular instantiate GraphqlModule
        const graphql = TestBed.get(Graphql) as Graphql;

        expect(serverDomainSpy.calls.count()).toBe(1, 'ServerConfigs.ServerDomain was not used.');
        expect(serverPortSpy.calls.count()).toBe(1,  'ServerConfigs.ServerPort was not used.');

        expect(protocolSpy.calls.count()).toBe(1, 'GraphqlConfigs.EndpointProtocol was not used.');
        expect(endpointNameSpy.calls.count()).toBe(1,  'GraphqlConfigs.EndpointName was not used.');

        done();
    });
});

按原样,测试通过并正常工作,但如果我不使用以下(无用的)行const graphql = TestBed.get(Graphql) as Graphql;GraphqlModule 在测试执行后会被实例化,这会使测试失败。

由于提供Graphql 服务的是GraphqlModule,我知道当我执行TestBed.get(Graphql) 时会触发Angular 中的一些延迟加载算法。没关系...我的问题是,有没有办法让我的模块以更explicit的方式加载?

这是 GraphqlModule 类的定义:

imports...

@NgModule({
    imports: [
        CommonModule,
        HttpClientModule,
        ApolloModule,
        HttpLinkModule
    ],
    declarations: [],

    providers: [
        Graphql, // Is an alias for Apollo
        GraphqlConfigs
    ]
})
export class GraphqlModule {

    constructor(
        @Optional() @SkipSelf() parentModule: GraphqlModule,
        graphql: Graphql,
        httpLink: HttpLink,
        serverConfigs: ServerConfigs,
        graphqlConfigs: GraphqlConfigs
    ) {

        // Making sure this is not imported twice.
        // https://angular.io/guide/ngmodule#prevent-reimport-of-the-coremodule
        if (parentModule) {
            throw new Error(
                'GraphqlModule is already loaded. Import it in the '+CoreModule.name+' only.');
        }

        // Gql setup:


        const gqlHttpLink = httpLink.create({
            uri: GraphqlModule.buildEndpointUrl(serverConfigs, graphqlConfigs)
        });

        graphql.create({
            link: gqlHttpLink,
            cache: new InMemoryCache(),
        });
    }

    private static buildEndpointUrl(serverConfigs: ServerConfigs, graphqlConfigs: GraphqlConfigs): string {

        return graphqlConfigs.EndpointProtocol +                            // eg. http://
            serverConfigs.ServerDomain+":"+serverConfigs.ServerPort+'/' +   // eg. example.com:80/
            graphqlConfigs.EndpointName;                                    // eg. graphql
    }
}

【问题讨论】:

  • 不清楚您在测试什么,因为问题不包含 GraphqlModule 或 Graphql。 我正在尝试测试我的模块构造函数之一中的代码 - 它没有列出。
  • @estus 该模块列在Testbed 的导入配置中。此测试是测试套件的一部分,用于测试 GraphqlModule 的不同功能
  • 对不起,我把它放在问题的正文中,但是我不确定它是否与我的问题有关。
  • 有必要了解发生了什么,谢谢。

标签: angular testing jasmine


【解决方案1】:

Graphql 已经在 GraphqlModule 根注入器的构造函数中实例化,并且 GraphqlModule 在 TestBed imports 中指定时被急切地实例化。不涉及延迟加载。

正如this answer 中所解释的,TestBed 注入器在第一个inject 回调调用、TestBed.getTestBed.createComponent 调用时被实例化。注入器在第一次注入之前不存在,因此不要使用任何模块或提供程序实例。由于几乎所有 TestBed 测试都至少在 itbeforeEach 中执行这些调用之一,因此通常不会出现此问题。

由于此测试不需要graphql 实例,因此为了通过测试,只需:

TestBed.get(Injector);

或者:

TestBed.get(TestBed);

另外,.compileComponents().then(() => { ... })done() 是不必要的,测试不涉及组件并且是同步的。

需要手动实例化注入器这一事实表明,此测试不需要 TestBed,尽管它是有益的,因为这样可以测试 GraphqlModule 构造函数 DI 注释,包括 parentModule 的注释。

【讨论】:

  • 哇,史诗般的答案。谢谢!
  • @Estus 我的测试失败,因为 (@Optional() @SkipSelf() parentModule: GraphqlModule) 出现错误属性名称预期的字符串类型,但我使用的是 ngMock。当我从模块构造函数中删除 parentModule 属性时它工作正常
猜你喜欢
  • 2013-05-26
  • 2018-09-14
  • 2017-06-07
  • 1970-01-01
  • 2014-09-16
  • 2012-12-29
  • 1970-01-01
  • 2013-09-28
  • 2019-05-02
相关资源
最近更新 更多