Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 使用TestBed.inject的角度单元测试根据测试执行顺序成功/失败_Angular_Typescript_Unit Testing_Jestjs - Fatal编程技术网

Angular 使用TestBed.inject的角度单元测试根据测试执行顺序成功/失败

Angular 使用TestBed.inject的角度单元测试根据测试执行顺序成功/失败,angular,typescript,unit-testing,jestjs,Angular,Typescript,Unit Testing,Jestjs,我有一个angular应用程序(v11.1.0),使用Jest进行单元测试 我使用TestBed.inject在单个测试中获取服务实例,并监视它们要测试的方法,或者调用或模拟返回值 但是,在切换到Typescriptstrict模式后,测试失败。但是如果我改变一些测试的顺序,一切都会顺利进行。 模拟服务似乎仍然在不同的单元测试之间交互 我尝试使用jest.resetAllMocks(),但它也不能解决问题。下面是我使用的代码: 单元测试 describe('AppComponent', () =

我有一个angular应用程序(v11.1.0),使用Jest进行单元测试

我使用
TestBed.inject
在单个测试中获取服务实例,并监视它们要测试的方法,或者调用或模拟返回值

但是,在切换到Typescript
strict
模式后,测试失败。但是如果我改变一些测试的顺序,一切都会顺利进行。 模拟服务似乎仍然在不同的单元测试之间交互

我尝试使用
jest.resetAllMocks()
,但它也不能解决问题。下面是我使用的代码:

单元测试

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        imports: [
          RouterTestingModule,
          HttpClientTestingModule,
          TranslateModule.forRoot(),
        ],
        declarations: [AppComponent],
        providers: [
          { provide: InformationService, useValue: informationServiceMock }
        ],
      }).compileComponents();
    })
  );

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  });

 describe('Test set', () => {
    it(`should have default text`, () => {
      fixture.detectChanges();
      expect(component.maintenanceBannerMessage).toBe('BANNER DE');
      expect(component.maintenanceBannerTitle).toBe('TITLE DE');
    });

    it(`Should open function`, () => {
      const dialog = TestBed.inject(MatDialog);
      const informationService = TestBed.inject(InformationService);
      jest.spyOn(informationService, 'updateOverlayAction');
      jest.spyOn(dialog, 'open');
      fixture.detectChanges();

      expect(dialog.open).toHaveBeenCalled();
      expect(informationService.updateOverlayAction).toHaveBeenCalled();
    });

    //------------------------------------------------------------
    // If I move this test in 2. position, the test `Should open function` FAILS
    // as getAnnouncementsByType keeps returning null instead of getting it from the
    // informationServiceMock provided in the configureTestingModule

    it(`should not be showed`, () => {
      const informationService = TestBed.inject(InformationService);
      jest
        .spyOn(informationService, 'getAnnouncementsByType')
        .mockReturnValue(of(null as any));
      fixture.detectChanges();

      expect(component.maintenanceBannerMessage).toBeUndefined();
      expect(component.maintenanceBannerTitle).toBeUndefined();
    });
    //------------------------------------------------------------

    it(`should not be showed`, () => {
      const dialog = TestBed.inject(MatDialog);
     const informationService = TestBed.inject(InformationService);
      jest
        .spyOn(informationService, 'getAnnouncementsByType')
        .mockReturnValue(of(null as any));
      jest.spyOn(dialog, 'open');
      fixture.detectChanges();

      expect(dialog.open).not.toHaveBeenCalled();
    });
  });
});
this.informationService.getAnnouncementsByType(AnnouncementType.BANNER)
  .pipe(takeUntil(this.destroy$))
  .subscribe(([currentLanguage, banners]) => {
    if (banners?.length > 0) {
      if (banners[0].title) {
        this.maintenanceBannerTitle = banners[0].title[currentLanguage.key as keyof LanguageObject];
      }
      if (banners[0].text) {
        this.maintenanceBannerMessage =
          banners[0].text[currentLanguage.key as keyof LanguageObject];
      }
    }
  });
应用程序组件

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        imports: [
          RouterTestingModule,
          HttpClientTestingModule,
          TranslateModule.forRoot(),
        ],
        declarations: [AppComponent],
        providers: [
          { provide: InformationService, useValue: informationServiceMock }
        ],
      }).compileComponents();
    })
  );

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  });

 describe('Test set', () => {
    it(`should have default text`, () => {
      fixture.detectChanges();
      expect(component.maintenanceBannerMessage).toBe('BANNER DE');
      expect(component.maintenanceBannerTitle).toBe('TITLE DE');
    });

    it(`Should open function`, () => {
      const dialog = TestBed.inject(MatDialog);
      const informationService = TestBed.inject(InformationService);
      jest.spyOn(informationService, 'updateOverlayAction');
      jest.spyOn(dialog, 'open');
      fixture.detectChanges();

      expect(dialog.open).toHaveBeenCalled();
      expect(informationService.updateOverlayAction).toHaveBeenCalled();
    });

    //------------------------------------------------------------
    // If I move this test in 2. position, the test `Should open function` FAILS
    // as getAnnouncementsByType keeps returning null instead of getting it from the
    // informationServiceMock provided in the configureTestingModule

    it(`should not be showed`, () => {
      const informationService = TestBed.inject(InformationService);
      jest
        .spyOn(informationService, 'getAnnouncementsByType')
        .mockReturnValue(of(null as any));
      fixture.detectChanges();

      expect(component.maintenanceBannerMessage).toBeUndefined();
      expect(component.maintenanceBannerTitle).toBeUndefined();
    });
    //------------------------------------------------------------

    it(`should not be showed`, () => {
      const dialog = TestBed.inject(MatDialog);
     const informationService = TestBed.inject(InformationService);
      jest
        .spyOn(informationService, 'getAnnouncementsByType')
        .mockReturnValue(of(null as any));
      jest.spyOn(dialog, 'open');
      fixture.detectChanges();

      expect(dialog.open).not.toHaveBeenCalled();
    });
  });
});
this.informationService.getAnnouncementsByType(AnnouncementType.BANNER)
  .pipe(takeUntil(this.destroy$))
  .subscribe(([currentLanguage, banners]) => {
    if (banners?.length > 0) {
      if (banners[0].title) {
        this.maintenanceBannerTitle = banners[0].title[currentLanguage.key as keyof LanguageObject];
      }
      if (banners[0].text) {
        this.maintenanceBannerMessage =
          banners[0].text[currentLanguage.key as keyof LanguageObject];
      }
    }
  });

测试特定的间谍应该恢复到所有测试中常见的一些实现中,不这样做会导致测试交叉污染,因为测试会影响后续测试

jest.resetAllMocks()
提供了不受欢迎的行为,应该避免。当在每个之前的
中使用时,它会毫无例外地重置所有间谍的实现,并使它们成为存根。在试验中使用时,也会导致试验交叉污染。如果需要重置特定的间谍实施,可以使用
mockReset()
完成


根据经验,
jest.restoreAllMocks()
应该在每个
之前的
中使用,它将使用
jest.spyOn
创建的所有间谍还原到原始实现中,以防有任何间谍。这种行为通常适用于所有测试,因此可以在Jest配置中启用。

不清楚它与TS的关系。它不会影响它在运行时的工作方式。你是说总是很紧张吗?我也不认为这有什么关系。我在重构代码时提到了它,添加了
strict
模式和模板检查。它似乎与模拟测试有关,因为它颠倒了它们运行的顺序,因此它不应该与代码本身有关,而应该与之前的模拟值有关,这些模拟值在测试中保持持久化,不清楚在调用getAnnouncementsByType的哪一点
jest.resetAllMocks()
不仅应该尝试,而且应该永久使用。这种行为和它完全一样吗?将其移动到beforeach或更好,在2的Jest config.中启用它。测试,我不模拟
getAnnouncementsByType
,因为我想测试“快乐路径”,因此是app.component中的默认值。在组件中调用此方法。但是如果我运行3。在2.之前进行测试,
getAnnouncementsByType
在组件中返回null。好像测试将“记住”上一个返回
null
的模拟值。在beforeach中添加
jest.resetAllMocks()
会触发
subscribe()
方法中组件中的异常,因为返回的可观察对象未定义。所以我暂时把它拿走了。我明白了。我在没有注意的情况下粘贴了resetAllMocks。resetAllMocks不应该用于开玩笑,这是有害的。改用restoreallmock等。就好像测试会“记住”以前返回null的模拟值一样——它确实记住了,这就是为什么在每次测试之前一致地将模拟恢复到原始状态很重要。