Невозможно «подписаться» на «Observable» для запроса http-get в файле спецификации

Я хочу протестировать следующую службу, которая возвращает наблюдаемое:

 public getData(str:string) {
    // return an observable
    return this.http.get(‘calltoserviceapi’+str)
        .map( (responseData) => {

            return responseData.json().Abc;
        })
        .map((s: Array<any>) => {
            let result:Array<AbcModel> = [];
            if (s) {
                s.forEach((s) => {
                    result.push(
                        new AbcModel(s.Val1,
                            s.Val2,
                            ));
                });
            }
            return result;
        });
}

мой файл спецификации:

fdescribe ("my-service.spec.js", ()=> {

    beforeEachProviders(() => [
        MyService,
        BaseRequestOptions,
        MockBackend,
        provide(Http, {
            useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
                return new Http(backend, defaultOptions);
            },
            deps: [MockBackend, BaseRequestOptions]
        }),
        provide(XHRBackend, {useClass: MockBackend})
    ]);



fit('should get response',inject([XHRBackend, MyService], (mockBackend, service) => {
        console.log("inside fit");
        let response = "something returned from service";
        let responseOptions = new ResponseOptions({ body: response });

        mockBackend.connections.subscribe((connection: MockConnection) => {
                connection.mockRespond(new Response(responseOptions));
        });

        service.getData('xyz').subscribe((a: MyModel[]) => {
                    expect(a.length).toBe(11); //this is NOT failing
              expect(a).toContain(“something”);

                }); //debugger not going inside subscribe

    }));

При отладке метод подписки не выполняется. в результате мой тестовый пример проходит без выполнения. что мне не хватает ?
P.S: MyService в данный момент не используется/не вызывается внутри компонента.


person candidJ    schedule 02.06.2016    source источник


Ответы (2)


Я думаю, вам нужно добавить async(...)

fit('should get response',async(inject([XHRBackend, MyService], (mockBackend, service) => {

чтобы тест ждал, пока не будут выполнены все асинхронные задачи. В противном случае будет запланировано выполнение http.get() задач, после чего тест завершится.

person Günter Zöchbauer    schedule 02.06.2016
comment
по какой-то причине webstorm выдает TS2345: Argument of type 'Function' is not assignable to parameter of type '(done: DoneFn) => void'. Type 'Function' provides no match for the signature '(done: DoneFn): void' при использовании только inject или async(inject(.. - person candidJ; 02.06.2016
comment
я немного запутался, почему мы используем mockbackend, если мы собираемся ждать, пока сервисный API что-то вернет. - person candidJ; 02.06.2016
comment
Какую версию Angular2 вы используете? Я не понимаю вашего последнего комментария. mockbackend используется для предотвращения обращений к серверу и предоставления ответа внутри теста. API службы ведет себя так же, как если бы вызов был сделан на сервер (даже если на самом деле это не так). - person Günter Zöchbauer; 02.06.2016
comment
Именно это я и имею в виду. Но все же отладчик не заходит в метод subscribe. - person candidJ; 02.06.2016
comment
Потому что без каких-либо средств, чтобы заставить тест ждать завершения асинхронных вызовов, тест заканчивается сразу после того, как асинхронные вызовы (http.get()) запланированы (но еще не выполнены). - person Günter Zöchbauer; 02.06.2016
comment
хммм.... Я использую async(inject(.., как вы сказали. я должен использовать .delay(10000) где-нибудь или любой другой обходной путь? - person candidJ; 02.06.2016
comment
Вам удалось избавиться от исключения, упомянутого в вашем первом комментарии? Не должно быть необходимости вызывать .delay(). Какую версию Angular2 вы используете? - person Günter Zöchbauer; 02.06.2016
comment
Да. angular :2.0.0-rc.1, rxjs: ".0.0-beta.6. - person candidJ; 02.06.2016
comment
Я не использую его сам, я просто слежу за проблемами в репозитории Angular GitHub. На самом деле я не знаю, какая версия поддерживает какое асинхронное тестирование. Это менялось почти с каждым обновлением в последние месяцы. Из того, что я знаю, последнее изменение заключалось в том, что использование async(...) должно ждать выполнения всех асинхронных вызовов, но эти изменения могут быть еще не включены в RC.1. Наверное только со следующим обновлением. - person Günter Zöchbauer; 02.06.2016
comment
@GünterZöchbauer, у меня та же проблема, и я попробовал предложенное вами решение (обернув все это внутри асинхронности), но мое тело подписки все еще не вызывается. Я заметил, что этот пост датирован 2016 годом, что-то изменилось с тех пор? - person Aiguo; 01.10.2017

наконец-то я нашел решение. Два изменения, которые я сделал:

  • используя async(), как указано @Gunter
  • упорядочить переданный ответ.

вот код:

fit('should get response',async(inject([XHRBackend, MyService], (mockBackend, service) => { //<--- wrap inside async call
    console.log("inside fit");
    let response = "something returned from service";
    let responseOptions = new ResponseOptions({ body: JSON.stringify(response) }); //<--- stringify the response

    mockBackend.connections.subscribe((connection: MockConnection) => {
            connection.mockRespond(new Response(responseOptions));
    });

    service.getData('xyz').subscribe((a) => {
                    expect(a.length).toBe(11); //will fail
                   expect(a).toContain(“something”); //will pass

                }); 

})));
person candidJ    schedule 06.06.2016