在 Jest 单元测试中的 Standalone 组件中模拟提供服务

问题描述 投票:0回答:1

我的服务未在根目录中提供,而是在我的组件中提供,如下所示:

@Injectable()
export class NavbarFacadeService extends AbstractStateFacade<IDrawerState, DrawerStateActions> implements OnDestroy {
   ...
}
@Component({
  selector: 'navbar-drawer',
  standalone: true,
  imports: [],
  providers: [NavbarFacadeService],
  template: `
     ...
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NavbarDrawerComponent implements AfterViewInit {
   ...
}

在组件中提供它而不是在根目录中提供它的原因是因为我希望在组件被销毁时自动清理服务。这工作正常。问题是对此进行单元测试。

在我的单元测试中,我应该能够像这样模拟 NavbarFacadeService 的实例:

const mockNavbarFacadeService = MockService(NavbarFacadeService, {
  ...
});

 beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [NavbarDrawerComponent],
      providers: [
        { provide: NavbarFacadeService, useValue: mockNavbarFacadeService },
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(NavbarDrawerComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

但是,当以这种方式提供时,当单元测试运行时,该服务不是模拟实例,而是实际提供的实例,并且正在执行真实的函数而不是我模拟的函数。

但是,如果我从组件中删除提供程序,然后返回到在根中提供服务,那么它会正确获取模拟实例。

那么,在使用提供服务的独立组件时,是否有其他方法可以设置 TestBed 来提供我不知道的模拟值?

angular unit-testing jestjs
1个回答
0
投票

Angular 将创建使用

@Injectable({providedIn: 'root'})
声明的服务的全局共享单个实例,另一方面,未使用
@Injectable({providedIn: 'root'})
声明的服务将在使用该服务的每个组件上具有单独的实例。

当您从服务中删除

{providedIn: 'root'}
时,您必须在组件中提供它,如下所示,否则构造函数中的注入将不起作用。

@Component({
  selector: 'xxx',
  providers: [Your_Service], // <-- here
})
export class AppComponent implements OnInit {
}

但是,当您运行测试用例时,模拟的服务将无法工作,因为该组件有自己的注入服务,当 TestBed 创建该组件时,Angualr 将创建该服务的一个新实例,该实例与您测试中的实例不同case,组件在运行测试用例时将使用该实例。

beforeEach(() => {
  fixture = TestBed.createComponent(AppComponent); // <-- Here
  component = fixture.componentInstance;
  fixture.detectChanges();
});

有两种方法可以解决这个问题

  1. 使用
    overrideProvider
beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [HttpClientTestingModule],
  }).compileComponents();
  TestBed.overrideProvider(DataService, {useValue: dataServiceMock}); // <--
});
  1. 使用
    overrideComponent
beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [HttpClientTestingModule],
  })
    .overrideComponent(ProductComponent, {
      set: {
        providers: [
          {provide: NavbarFacadeService, useValue: mockNavbarFacadeService},
        ]
      }
    }).compileComponents();
});
© www.soinside.com 2019 - 2024. All rights reserved.