angular - 使用 Karma 和 Jasmine/Angular 8 对具有多个并行 API 调用的服务进行单元测试

标签 angular api testing karma-jasmine

我正在尝试为一个服务和一个组件编写单元测试(Jasmine 和 Karma),其目的是使用两个不同的 URLS,获取人员和星舰数据。两个调用均通过 forkJoin 同时返回。

我的 App 组件调用 ApiService 执行两个调用,如下所示:

应用程序组件:

import {Component, OnInit} from '@angular/core';
import {ApiService} from '../services/api.service';

export class AppComponent implements OnInit {

  constructor(private apiService: ApiService) {}

onGetData() {
    this.apiService.getData().subscribe((data: any) => {

      this.peopleData = data[0];
      this.starshipData = data[1];

     });

  }

API 服务:

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

export class ApiService {
  constructor(private http: HttpClient) {}

  getData(): Observable<any[]> {
    const randomPeoplePage = Math.floor(Math.random() * 9) + 1;
    const peopleUrl = `https://swapi.co/api/people/?page=${randomPeoplePage}`;

    const randomStarshipsPage = Math.floor(Math.random() * 4) + 1;
    const starshipsUrl = `https://swapi.co/api/starships/?page=${randomStarshipsPage}`;

    const peopleProm = this.http.get(peopleUrl);
    const starshipProm = this.http.get(starshipsUrl);

    return forkJoin([peopleProm, starshipProm]);

  }
}

我对测试相当缺乏经验,尤其是在如何正确测试 API 调用方面。 在过去的几天里,我一直在尝试不同的解决方案,如下所示:

 it('should return an Observable', () => {
    const randomPeoplePage = Math.floor(Math.random() * 9) + 1;
    const randomStarshipsPage = Math.floor(Math.random() * 4) + 1;


    const dummyData = [
      {
        count: 87,
        next: `https://swapi.co/api/people/?page=${randomPeoplePage + 1}` || null,
        previous: `https://swapi.co/api/people/?page=${randomPeoplePage - 1}` || null,
        results: new Array(87)
      },
      {
        count: 37,
        next: `https://swapi.co/api/starships/?page=${randomStarshipsPage + 1}` || null,
        previous: `https://swapi.co/api/starships/?page=${randomStarshipsPage - 1}` || null,
        results: new Array(37)
      }
    ];

    service.getData().subscribe(data => {
      expect(data.length).toBe(2);
      expect(data).toEqual(dummyData);

      const peopleReq = httpMock.expectOne(`https://swapi.co/api/people/?page=${randomPeoplePage}`);
      const starshipReq = httpMock.expectOne(`https://swapi.co/api/starships/?page=${randomStarshipsPage}`);

      forkJoin([peopleReq, starshipReq]).subscribe(() => {
        expect(peopleReq.request.method).toBe('GET');
        expect(starshipReq .request.method).toBe('GET');
      })

      peopleReq.flush(dummyData[0]);
      starshipReq.flush(dummyData[1]);

    });


  });
});

但是这个测试没有通过,我真的不知道为什么或者我应该调查什么。 我是否需要在 api.service.spec.tsapp.component.spec.ts 中测试 API 调用? 如何模拟返回?我应该单独测试它们吗? 这是一项“学术”测试,因此欢迎任何有关最佳实践的提示。

非常感谢!

最佳答案

组件应包含与数据表示相关的逻辑。现在,您可以同时拥有智能组件。
对于智能组件,您可以测试与提供数据的外部服务(存储、路由、提供数据的服务)的交互,而对于您可以测试组件是否数据正确显示和/或@Output事件是否正确发送。

服务应包含业务逻辑(API 调用,可能存储数据等...),即与数据呈现不直接相关的逻辑。

在本例中,我只需为 getData() 提供一些预定义数据,这样我就可以确保不会调用真实 API。

  it('....', () => {
    const url1 = 'url1';
    const url2 = 'url2';

    const responseMap = {
      url1: { data: 'url1' },
      url2: { data: 'url2' }
    }

    // Assuming this is imported..    
    class ApiService {
      constructor (private http) { }

      getData () {
      }
    }

    const getSpy = jasmine.createSpy('Http.get').and.callFake((arg) => {
      return of(responseMap[arg]);
    });
    const mockHttp = { get: getSpy }
    const apiService = new ApiService(mockHttp);

    spyOn(apiService, 'getData').and.callFake(function () {
      return forkJoin([this.http.get(url1), this.http.get(url2)])
    });

    apiService.getData()
      .subscribe(([r1, r2]) => {
        expect(getSpy).toHaveBeenCalledWith(url1);
        expect(getSpy).toHaveBeenCalledWith(url2);

        expect(r1).toBe(responseMap['url1']);
        expect(r2).toBe(responseMap['url2']);
      })
  });

关于angular - 使用 Karma 和 Jasmine/Angular 8 对具有多个并行 API 调用的服务进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59923374/

相关文章:

javascript - Angular:如何将自定义指令中的索引变量共享给另一个指令?

html - 无法更改选项卡的高度,Angular 6 中的颜色

node.js - 在 Node.js 中模拟服务器 - 流分隔文件,暂停 1 秒

testing - 其他几个运行者在 testcafe 中的运行大师?

testing - Grails 2.0 集成测试污染?

javascript - 在 ion-item 中内联显示信息图标

angular - 查看销毁错误 : Attempt to use a destroyed view: detectChanges in Angular 4

java - 为什么要在 DAO 中创建扩展异常?

c++ - Win32 API 检查当前窗口是对话框还是普通窗口

azure - 如何将 API 数据加载到 Azure Synapse 中?