【问题标题】:Angular 8 karma test a service without injecting all service in the constructorAngular 8 karma 测试服务而不在构造函数中注入所有服务
【发布时间】:2021-06-20 09:09:22
【问题描述】:

我是使用 Karma 进行 Angular 测试的新手,我不了解如何正确测试服务。 假设我有必须测试的服务:

    @Injectable()
    export class MyService {
        constructor(private httpService: HttpService) { }

        //methods to test
    }

这是我的测试课:

    describe('MyService', () => {
      let service: MyService;
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          providers: [MyService],
        }).compileComponents();
        service = TestBed.get(MyService);
      }));
    });

当我运行 ng test 时,它会给出错误 NullInjectorError: No provider for HttpService!。
所以我将HttpService添加到测试类的providers数组中,这样:

    describe('MyService', () => {
      let service: MyService;
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          providers: [MyService, HttpService],
        }).compileComponents();
        service = TestBed.get(MyService);
      }));
    });

HttpService是这样的:

    @Injectable()
    export class HttpService{
        constructor(private httpService: HttpClient) { }
    }

所以现在我收到错误NullInjectorError: No provider for HttpClient!。 (HttpClient 来自@angular/common/http)。
如果我将 HttpClient 添加到测试类中的提供程序数组中,那么 HttpClient 构造函数中的所有服务/类都会出现相同的错误,依此类推。什么是建立服务的正确方法,而不必添加每个提供者,从而导致潜在的无限提供者?

【问题讨论】:

标签: angular testing karma-jasmine angular8 angular-test


【解决方案1】:

您应该使用HttpClientTestingModule 并通过HttpTestingController 和flush 方法模拟数据。这是一个关于我如何测试服务的 Angular 11 和 jasmine 3.6.0 示例。希望对你有帮助:

// Dependencies
import { TestBed, waitForAsync } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

// Assets
import { ExampleService } from './api/example.service';

describe('*[Example Service]: -----------------------------------------', () => {
    let httpTestingController: HttpTestingController;
    let service: ExampleService;

    beforeEach(waitForAsync(() => {
        TestBed.configureTestingModule({
            imports: [
             HttpClientTestingModule
            ]
        }).compileComponents();
        
      httpTestingController = TestBed.inject(HttpTestingController);
      service = TestBed.inject(ExampleService);
    }));
    
    it('1). should get data from GET service', waitForAsync( () => {
      // Arrange
      const expectedData: string[] = ['data1', 'data2'];
      let apiError, apiData;
      // Action
      service.getData().subscribe(response => {
        apiData = response;
      }, error => {
        apiError = error;
      });
      const request = httpTestingController.expectOne(`http://localhost:3000/example`);
      request.flush(expectedData);
      // Assert
      expect(apiData.length).toEqual(2);
      expect(apiError).toBeUndefined();
        }));

});

【讨论】:

    【解决方案2】:

    在您的 Testbed 配置中,导入 HttpClientTestingModule

      beforeEach(async(() => {
        TestBed.configureTestingModule({
          imports: [HttpClientTestingModule],
          providers: [MyService, HttpService],
        }).compileComponents();
        service = TestBed.get(MyService);
      }));
    

    你也可以考虑

    1. 将TestBed.get(MyService); 更改为TestBed.inject(MyService);,因为TestBed.get(...) 已弃用What's the difference between TestBed.get and new Service(...dependencies)

    2. 将async 更改为waitForAsync,因为async 已弃用When to use waitForAsync in angular

    【讨论】:

    • 您好,谢谢您的回答。所以这个解决方案是针对我的情况的,但是有没有一种正确的方法来测试一般的服务,而不必导入它使用的所有服务?像避免导入链的常用方法?
    猜你喜欢
    • 1970-01-01
    • 2020-06-03
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2018-01-10
    • 2017-12-03
    • 1970-01-01
    相关资源
    最近更新 更多