如何在@ngrx/data 中对 EntityCollectionServiceBase 进行单元测试?

How to unit test a EntityCollectionServiceBase in @ngrx/data?

我有一个虚拟服务:

export class PatientService extends EntityCollectionServiceBase<Patient> {
  constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory) {
    super('Patient', serviceElementsFactory);
  }
}

我有以下测试:

describe('PatientService', () => {
  let service: PatientService;

  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(PatientService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

它给了我:

NullInjectorError: No provider for EntityCollectionServiceElementsFactory

所以我更新如下:

describe('PatientService', () => {
  let service: PatientService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [EntityDataModuleWithoutEffects.forRoot(entityConfig)],
      providers: [provideMockStore()],
    });
    service = TestBed.inject(PatientService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

但现在它给了我:

NullInjectorError: No provider for ScannedActionsSubject!

如何正确修复我的测试?

您必须设置整个数据模块,就像在 "normal Angular module" 中一样。

这意味着,提供商店、效果和数据实体。

可能有更好的方法,但是...我不知道 ‍♂️

是的,你们很亲近,就这样吧。您需要在测试台中提供配置所需的一切。

在我们的例子中,这意味着 PatientService 应该作为测试单元提供,EntityCollectionServiceElementsFactory 应该作为它的依赖项提供。

但是 EntityCollectionServiceElementsFactory 有自己的依赖项:EntityDispatcherFactoryEntityDefinitionServiceEntitySelectorsFactoryEntitySelectors$Factory。我们不想提供,因为它们可能有自己的依赖关系,使我们的生活变得更糟。

要修复它,我们只需将 EntityCollectionServiceElementsFactory.

describe('PatientService', () => {
  let service: PatientService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        PatientService,
        {
          provide: EntityCollectionServiceElementsFactory,
          // our stub
          useValue: {
            methodsToFake: jasmine.createSpy(),
            // ....
          },
        },
      ],
    });
    service = TestBed.inject(PatientService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

此外,为了避免将来模拟依赖项及其方法的痛苦,您可以使用 ng-mocks。然后测试看起来像这样:

describe('PatientService', () => {
  let service: PatientService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        PatientService,
        {
          provide: EntityCollectionServiceElementsFactory,
          useValue: MockService(EntityCollectionServiceElementsFactory),
        },
      ],
    });
    service = TestBed.inject(PatientService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

如果您只需要消除错误,您可以像这样导入所有必需的模块:

   beforeEach(() => {
     TestBed.configureTestingModule({
       imports: [HttpClientTestingModule, EffectsModule.forRoot([]), StoreModule.forRoot({}), EntityDataModule.forRoot(entityConfig)],
     });
     service = TestBed.inject(PatientService);
   });