如何在服务模拟中测试可观察的更改?

时间:2019-08-23 11:43:03

标签: angular unit-testing asynchronous observable

我必须测试一个后端服务存根,该存根返回一个可观察值。 存根方法:

public postStatus(handle: string): Observable<StatusReturn>{
    setTimeout(() => {
      this.result = {
        currentlyProcessedFileName: 'datei2.pdf',
        errParams: [],
        numFiles: 3,
        numFilesAlreadyProcessed: 1,
        numTasksBefore: 0,
        processingStatus: 1,
        technicalRetCode: 0
      };
    }, 5000);
    setTimeout(() => {
      this.result = {
        currentlyProcessedFileName: '',
        errParams: [],
        numFiles: 3,
        numFilesAlreadyProcessed: 3,
        numTasksBefore: -1,
        processingStatus: 2,
        technicalRetCode: 0
      };
    }, 10000);
    return of(this.result);
  }

其他信息:结果在服务级别初始化,因此setTimeout仅更新这些参数。

我已经尝试了很多,但是我的“最接近”方法是:

fit('postStatus should return changeing Observable<StatusReturn> with correct second sample data after 5000ms', fakeAsync(() => {
    // WHEN
    const secondReturn = {
      currentlyProcessedFileName: 'datei2.pdf',
      errParams: [],
      numFiles: 3,
      numFilesAlreadyProcessed: 1,
      numTasksBefore: 0,
      processingStatus: 1,
      technicalRetCode: 0
    };
    let result;

    // DO
    service.postStatus('handle').subscribe((res) => {
      result = res;
    });
    tick(5001);

    expect(result).toEqual(secondReturn);
  }));

测试给出以下错误:

Expected $.currentlyProcessedFileName = '' to equal 'datei2.pdf'.
Expected $.numFilesAlreadyProcessed = 0 to equal 1.
Expected $.numTasksBefore = 1 to equal 0.
Expected $.processingStatus = 0 to equal 1.

其中左侧是初始数据(因此我从可观察的数据中获取数据)和

Error: 1 timer(s) still in the queue.

表示已启动第一次数据更新。我可以通过将tick(5001)更改为tick(4999)并在队列中有两个计时器来批准此操作。

我正在寻找有关如何使用新的可观察值更新结果变量的建议。

1 个答案:

答案 0 :(得分:2)

我认为您的职能正在做您想要做的事情以外的事情。 我们可以通过添加一些console.log语句来进行测试。

service.postStatus('handle').subscribe((res) => {
    console.log('setting return');
    result = res;
});
console.log(`result is ${result}`);

tick(5001);
console.log('tick 5001 occurred');
  

日志:“设置收益”

     

日志:“结果未定义”

     

日志:“打勾5001”

这告诉我们您的订阅立即返回,因为这是我们看到的第一个控制台日志。由于计时器尚未触发,因此结果不确定。

由于您要返回一个可观察值并期望它具有两个不同的结果,因此我想为您的被测方法提出一种略有不同的方法。我们可以如下返回Subject<StatusReturn>

public postStatus(handle: string): Observable<StatusReturn> {
    const currentStatus = new Subject<StatusReturn>();

    setTimeout(() => {
        this.result = {
            currentlyProcessedFileName: 'datei2.pdf',
            errParams: [],
            numFiles: 3,
            numFilesAlreadyProcessed: 1,
            numTasksBefore: 0,
            processingStatus: 1,
            technicalRetCode: 0
        };
        currentStatus.next(this.result);
    }, 5000);
    setTimeout(() => {
        this.result = {
            currentlyProcessedFileName: '',
            errParams: [],
            numFiles: 3,
            numFilesAlreadyProcessed: 3,
            numTasksBefore: -1,
            processingStatus: 2,
            technicalRetCode: 0
        };
        currentStatus.next(this.result);
    }, 10000);
    return currentStatus;
}

是否通知我正在打电话给currentStatus.next(this.result),以告知受试者结果已更改?

使用此功能后,您可以稍微更改一下测试以使其看起来像

fit('postStatus should return changing Observable<StatusReturn> with correct second sample data after 5000ms', fakeAsync(() => {
    // WHEN
    const secondReturn = {
        currentlyProcessedFileName: 'datei2.pdf',
        errParams: [],
        numFiles: 3,
        numFilesAlreadyProcessed: 1,
        numTasksBefore: 0,
        processingStatus: 1,
        technicalRetCode: 0
    };
    let result;

    // DO
    service.postStatus('handle').subscribe((res) => {
        result = res;
    });

    tick(5001);
    const firstResult = result;

    expect(result).toEqual(secondReturn);

    tick(5001); // clear the queue
    expect(result).not.toEqual(firstResult);
}));