【问题标题】:Angular test fails despite console logging correct value尽管控制台记录了正确的值,但角度测试仍失败
【发布时间】:2022-11-17 22:04:34
【问题描述】:

我有一个 Angular 组件,正在测试一个函数调用。该函数调用一个服务函数,我正在尝试测试该服务函数是否被正确调用。

零件:

 loadAllDocuments( event = null ): void {
    this.clientDocService.setDocuments([]);
    const key = `clients/documents/000/000/${this.clientId}/original`;

    this.s3.getBucketContents(key).then( data => {
      const contentLength = data.Contents.length
      let foundLength = 0
      let missingLength = 0
      for ( const entry of data.Contents ) {
        const dataParams = {name: entry.name}
        this.clientDocService.addToDocuments(dataParams)
        this.clientDocService.createClientDocIfMissing(dataParams).subscribe(doc => {
          doc ? missingLength += 1 : foundLength += 1
        })

        if (missingLength + foundLength === contentLength) {
          const message = `Found ${contentLength} documents in storage. ${foundLength} were already here and ${missingLength} were new`

          // What I am testing
          this.global.handleResponse(message)

          // logs 'Found 1 documents in storage. 0 were already here and 1 were new' to console
          console.log(message)
        }
      }
    })

    if (event) event.target.complete();
  }

我的测试:

describe('DocumentsPage', () => {
  let component: DocumentsPage;
  let fixture: ComponentFixture<DocumentsPage>;
  const mockGlobalsService = jasmine.createSpyObj('GlobalsService', ['base_url', 'handleResponse'])
  const mockS3Service = jasmine.createSpyObj('S3_Service', ['getBucketContents'])
  const mockClientDocService = jasmine.createSpyObj('ClientDocService', ['setDocuments', 'createClientDocIfMissing', 'addToDocuments', 'addToAWSDocs', 'fetchClientAndSignedDocuments', 'setMergedDocuments'])

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ DocumentsPage ],
      imports: [HttpClientTestingModule,],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers: [
        { provide: GlobalsService, useValue: mockGlobalsService },
        { provide: S3_Service, useValue: mockS3Service },
        ExternalDocumentsService,
        { provide: ClientDocService, useValue: mockClientDocService },
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    mockClientDocService.mergedDocuments$ = of([])
    fixture = TestBed.createComponent(DocumentsPage);
    component = fixture.componentInstance;
    service = TestBed.inject(ClientDocService)
    fixture.detectChanges();
  });

  describe('loadAllDocuments', () => {
    it('', () => {
      const mockBucketContents = {
        Contents: [
          {name: 'test 1', Key: 'x'},
        ]
      }
      mockS3Service.getBucketContents.and.returnValue(new Promise((res) => res(mockBucketContents)))
      mockClientDocService.createClientDocIfMissing.and.returnValue(of([{name: 'test 2', Key: 'y'}]))

      component.loadAllDocuments()

      // Fails despite value being logged
      expect(mockGlobalsService.handleResponse).toHaveBeenCalledOnceWith('Found 1 documents in storage. 0 were already here and 1 were new')
    })
  })
});

测试失败并响应:

Expected spy GlobalsService.handleResponse to have been called only once, and with given args:
  [ 'Found 1 documents in storage. 0 were already here and 1 were new' ]
But it was never called.

我不确定我是在错误地嘲笑电话还是什么?

【问题讨论】:

    标签: angular jasmine


    【解决方案1】:

    这与代码的异步性质有关,.then

    您看到它已注销,但它会在您断言后的稍后时间点注销。

    修复它的一种方法是使用async/fixture.whenStable()

    // !! add async here
    describe('loadAllDocuments', () => {
        it('', async () => {
          const mockBucketContents = {
            Contents: [
              {name: 'test 1', Key: 'x'},
            ]
          }
          mockS3Service.getBucketContents.and.returnValue(new Promise((res) => res(mockBucketContents)))
          mockClientDocService.createClientDocIfMissing.and.returnValue(of([{name: 'test 2', Key: 'y'}]))
    
          component.loadAllDocuments();
          
          // !! wait until all pending promises have completed before continuing
          await fixture.whenStable();
    
          // Fails despite value being logged
          expect(mockGlobalsService.handleResponse).toHaveBeenCalledOnceWith('Found 1 documents in storage. 0 were already here and 1 were new')
        })
      })
    

    另一种解决方法是使用fakeAsync/tick

    // !! Wrap callback with fakeAsync, pay attention to the extra brackets
    describe('loadAllDocuments', () => {
        it('', fakeAsync(() => {
          const mockBucketContents = {
            Contents: [
              {name: 'test 1', Key: 'x'},
            ]
          }
          mockS3Service.getBucketContents.and.returnValue(new Promise((res) => res(mockBucketContents)))
          mockClientDocService.createClientDocIfMissing.and.returnValue(of([{name: 'test 2', Key: 'y'}]))
    
          component.loadAllDocuments()
          
          // !! call tick to say finish all pending promises before continuing
          tick();
    
          // Fails despite value being logged
          expect(mockGlobalsService.handleResponse).toHaveBeenCalledOnceWith('Found 1 documents in storage. 0 were already here and 1 were new')
        }))
      })
    

    【讨论】:

    • 我不得不将 async 放在 it() 电话上而不是 describe() 上,但这样做成功了!谢谢
    • 如果 JeremyThomas 解决了您的问题,请记得接受@aliF50 的回答 :)
    • 哦,是的,我把asyncfakeAsync 放在了错误的地方。我已经更正了,对此感到抱歉。
    猜你喜欢
    • 2022-11-19
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多