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

Jua*_*era 10 unit-testing ngrx angular ngrx-data

我有一个虚拟服务:

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

我有以下测试:

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

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

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});
Run Code Online (Sandbox Code Playgroud)

它给了我:

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();
  });
});
Run Code Online (Sandbox Code Playgroud)

但现在它给了我:

NullInjectorError: No provider for ScannedActionsSubject!

我怎样才能正确修复我的测试?

sat*_*ime 6

更新于 2022-08-06

由于最新版本的变化ngrx,您需要导入一个空的存储模块和HttpClientTestingModule.

请检查下面的示例:

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

  beforeEach(() => {

    TestBed.configureTestingModule({
      providers: [
        PatientService, // <- your entity collection service

        // a way to mock the store selectors
        provideMockStore(),
      ],
      imports: [
        EntityDataModule.forRoot({
          entityMetadata: {
            Patient: {}, // <- change to your entity
          },
          pluralNames: {
            Patient: 'Patients',  // <- change to your entity
          },
        }),

        // can be kept as it is if there are no more dependencies
        StoreModule.forRoot({}),
        EffectsModule.forRoot([]),
        HttpClientTestingModule,
      ],
    });
    service = TestBed.inject(PatientService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});
Run Code Online (Sandbox Code Playgroud)

原答案

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

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

EntityCollectionServiceElementsFactory有自己的依赖关系:EntityDispatcherFactoryEntityDefinitionService和。我们不想提供这些,因为它们可能有自己的依赖关系,使我们的生活变得更糟。EntitySelectorsFactoryEntitySelectors$Factory

要修复它,我们只需 sub 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();
  });
});
Run Code Online (Sandbox Code Playgroud)

另外,为了避免将来模拟依赖项及其方法的痛苦,您可以使用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();
  });
});
Run Code Online (Sandbox Code Playgroud)

  • 我尝试使用 ngmocks,但正在检索 TypeError: Cannot destruct property 'dispatcher' of 'serviceElementsFactory.create(...)' 因为它未定义。 (5认同)