2017-07-26 104 views
3

我正在探索新的Angular HttpClientModule並運行到一個莫名其妙的錯誤。該模塊足夠新,我還找不到有關如何進行單元測試的任何有用信息,官方文檔中沒有任何示例。錯誤,而單元測試HttpClientModule(Angular 4.3+)

該應用程序包含一種方法的服務,該方法將URL傳遞到http.get。當我在瀏覽器上下文(又名ng serve)中調用此方法時,http調用正常執行。當在單元測試的情況下叫,我得到以下錯誤:

TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

這是角CLI產生最小的應用程序。下面是相關代碼:

app.module.ts:

import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { HttpClientModule } from '@angular/common/http'; 
import { AppComponent } from './app.component'; 

@NgModule({ 
    declarations: [AppComponent], 
    imports: [BrowserModule, HttpClientModule], 
    providers: [], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

app.component.ts:

import { Component, OnInit } from '@angular/core'; 
import { TestService } from './test.service' 

@Component({ 
    selector: 'app-root', 
    templateUrl: './app.component.html', 
    styleUrls: ['./app.component.css'], 
    providers: [TestService] 
}) 
export class AppComponent { 
    title = 'app'; 

    constructor(private testSvc: TestService) {} 

    ngOnInit() { 
    this.testSvc.executeGet('http://www.example.com'); 
    } 
} 

test.service.ts:

import { Injectable } from '@angular/core'; 
import { HttpClient } from '@angular/common/http'; 

@Injectable() 
export class TestService { 
    constructor(private http:HttpClient) {} 

    executeGet(url:string) { 
    this.http.get(url) 
     .subscribe(
     data => console.log('success', data), 
     error => console.log('error', error) 
    ); 
    } 
} 

test.service.spec.ts:

import { HttpClient, HttpHandler } from '@angular/common/http'; 
import { TestBed, inject } from '@angular/core/testing'; 
import { TestService } from './test.service'; 

describe('TestService',() => { 
    beforeEach(() => { 
    TestBed.configureTestingModule({ 
     providers: [HttpClient, HttpHandler, TestService] 
    }); 
    }); 

    it('should executeGet', inject([TestService], (svc: TestService) => { 
    expect(svc.executeGet).toBeDefined(); 
    // this is where the 'undefined' error occurs 
    svc.executeGet('http://www.example.com'); 
    })); 
}); 

任何指導或指針不勝感激。

TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

對於我這種錯誤的來源沒有使用HttpInterceptor正確:

+0

你真的需要一個真正的HttpClientModule?根據[文檔](https://angular.io/guide/http#testing-http-requests) - HTTP後端需要作爲良好測試練習的一部分進行模擬。 –

+0

@AleksandrPetrovskij我讀過可用的文檔。它非常薄,HttpClientModule足夠年輕,沒有太多關於如何使用它的第三方內容。我在嘗試使用HttpClientTestingModule時遇到了其他問題,但選擇不將它們包含在本文中,以便將它關注於「未定義」錯誤。 無論如何, –

回答

1

導入缺少

Here is the working example on plnkr

describe('TestService',() => { 
    beforeEach(() => { 
    TestBed.configureTestingModule({ 
     imports: [HttpClientModule], 
     providers: [TestService] 
    }); 
    }); 

    it('should executeGet',() => { 
    const testService = TestBed.get(TestService); 

    expect(testService.executeGet).toBeDefined(); 
    testService.executeGet('http://www.example.com'); 
    })); 
}); 
+0

謝謝你的例子。我很感激。也就是說,這並不能幫助我理解錯誤,也不能解釋爲什麼在沒有模擬的情況下進行單元測試是不可能的。我明白爲什麼嘲笑在測試中是一個好主意,但不是爲什麼在沒有模擬的情況下HTTP調用失敗,這是我的問題的關鍵。 –

+0

我認爲導入* HttpClientModule *失蹤,[示例](http://plnkr.co/edit/InyCCcl74EzzDXGo2owY) –

+0

就是這樣!再次感謝Aleksandr。如果你想更新你的答案或發佈不同的答案,我會很樂意接受。 –

3

最近,我在錯誤消息指出確切經歷過同樣的問題。如果您還提供自定義HttpInterceptor請確保您正確使用它。在下面的代碼片段中注意,如果錯誤狀態不是401,我錯過了返回Observable, Promise, Array, or Iterable。默認undefinedintercept方法返回,而不是Observable, Promise, Array, or Iterable,所以angular正在抱怨這一點。

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
    return next.handle(req).catch(err => { 
     if(err instanceof HttpErrorResponse) { 
     if(err.status === 401) { 
      this.store.dispatch(this.authAction.unauthorized(err)); 
      return Observable.throw(err); 
     } 
     } 
    }) 
    } 

並且修復程序爲以下代碼段。 HttpClientModule的

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
    return next.handle(req).catch(err => { 
     if(err instanceof HttpErrorResponse) { 
     if(err.status === 401) { 
      this.store.dispatch(this.authAction.unauthorized(err)); 
     } 
     } 
     return Observable.throw(err); //Actually this line of code 
    }) 
    } 
+0

我沒有使用HttpInterceptor。正如我之前提到的,'TestService.executeGet'在瀏覽器上下文中運行,但在單元測試中失敗。有一些關於環境差異的事情似乎是造成這個問題的原因。 –

+0

你如何單元測試攔截器。你有樣品可以分享嗎? – Angad