0

我有一个服务方法,它有一个服务调用(HTTP 调用),它立即订阅,并根据响应代码执行其余的操作命令。

示例:服务方法

processData(id): void {
    const url = `http://localhost:5000/data/${id}`;

    this.http.head(url).subscribe(() => {
        console.log('Success');

        // Rest of the code - TODO

    }, (error) => {
        console.log('Failed');        

        // Rest of the code - TODO

    });
}

我尝试了以下示例(测试用例)

fdescribe('ReportedFileService', () => {

    let service: DataService;
    let httpMock: HttpTestingController;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports:[HttpClientModule, HttpClientTestingModule],
            providers:[DataService]
        });
        service = TestBed.get(DataService);
        httpMock = TestBed.get(HttpTestingController);
    });

    afterEach(() => {
        httpMock.verify();
    });

    fit('should be valid', () => {
        const id = 1;
        const filePath = `http://localhost:5000/data/${id}`;

        const req = httpMock.expectOne(filePath);

        expect(req.request.method).toEqual('Head');

        const response = service.processData(id);
    })
}

请帮助我如何处理这种情况。

4

1 回答 1

1

您的服务不应该订阅 HttpClient observable,因此,它不应该是一个 void 返回类型的方法。服务应该返回要订阅的 HttpClient 可观察对象。

例如

服务方式

@Injectable({ providedIn: 'root' }) //ensure service is provided at root level so it remains a singleton in the dependency injection tree.
...
constructor(http: HttpClient){}
...
processData(id): Observable<any> { //services should return an Observable
    const url = `http://localhost:5000/data/${id}`;
    return this.http.head(url); // ** your service method SHOULDN'T be subscribing to the HTTP call.
}

您的服务方法不应订阅 HTTP 调用。调用 .subscribe() 将导致发出 HTTP 请求。

使用该服务的组件将首先在构造函数中注入该服务。然后,您将订阅组件中的服务调用。

一些组件.ts

...
constructor(private dataService: DataService){}
...
someMethod(){
   this.processData().subscribe(
       (response) => { //subs
           console.log("success");
           // Rest of the code - TODO
       },
       (error) => {
           console.log('Failed');        

          // Rest of the code - TODO
       }
   )
}

然后,您的测试用例应该像组件一样订阅服务。

service.spec.ts - 你的服务测试用例

fit('should be valid', fakeAsync(() => {
   const id = 1;

   service.subscribe( //you are making the http call in the test case.
       (success: any) => {
          expect(success.request.headers.get('Content-Type').toEqual('application/json')); //assert that the http headers you will get back from the observable is similar to the one the mock backend will return.
       }
   )

   httpMock.expectOne({
      url: 'http://localhost:5000/data/${id}',
      method: 'HEAD'
   }).flush({}, { headers: { 'Content-Type': 'application/json' } }); //HEAD requests have empty response body but only headers

});

此外,您不应该调用 localhost,当您必须将此应用程序部署到 Web 服务器时,您必须手动更改每个字符串。

相反,您应该在环境文件中设置您的 API url,该文件位于:

然后,您可以通过以下方式将环境 url 作为字符串导入:

import { environment } from 'environments/environment';
...
const API_URL = environment.apiURL;

以下是一些对我有帮助的指南,我已添加书签:使用 Angular 的 HttpClient 模块发送 HTTP 请求: https ://www.techiediaries.com/angular-httpclient/

测试服务: https ://www.ng-conf.org/2019/angulars-httpclient-testing-depth/

于 2019-07-10T13:40:31.987 回答