单元测试一个调用promise返回函数的递归方法

时间:2016-12-22 14:38:53

标签: angularjs unit-testing typescript jasmine promise

下面是我要测试的代码的简化版本:一个定期清空的简单队列。对于队列中的每个号码,都会进行HTTP POST以将其发送到(在此示例中为虚构的)API地址。如果POST成功,则该号码将从队列中移出,并考虑下一个号码。

class Queue {
    queue: Array<number>;
    processingQueue: boolean;

    constructor(public $http: angular.IHttpService) {
        this.queue = new Array<number>();
        this.processingQueue = false;
    }

    startQueueProcessor() {
        this.processingQueue = false;

        setInterval(() => {
            if (!this.processingQueue)
                this.processQueue();
        }, 1000);
    }

    postNumber(number: number): angular.IHttpPromise<{}> {
        return this.$http.post('http://mydummyurl.com/givemeanumber', number);
    }

    processQueue(): void {
        this.processingQueue = true; // we are currently processing a queue, so make sure setInterval does not trigger another processing run

        if (this.queue.length !== 0) { // are there any numbers to deal with?
            const item = this.queue[0]; // get the first number in the queue

            this.postNumber(item) // POST it (returns a promise)
                .then(
                () => { // if successful...
                    this.queue.shift(); // we've dealt with this item, so remove it from the queue
                    this.processQueue(); // check the queue again (recurses until all items have been dealt with)
                },
                () => { // if unsuccessful...
                    this.processingQueue = false; // something went wrong, so stop
                }
                );
        } else {
            this.processingQueue = false; // queue is empty, stop processing
        }
    }

    enqueue(number: number): void { // add a number to the queue
        this.queue.push(number);
    }
}

我想要创建的测试将检查,在将三个项目添加到队列后,对processQueue()的单个调用将清空它。

像这样(在Jasmine中嘲笑):

describe('queueing', () => {
    var queueService;

    beforeEach(inject((_$httpBackend_, $injector) => {
        httpBackend = _$httpBackend_;
        httpBackend.whenPOST().respond(200);

        queueService = $injector.get('queue');
    }));

    it('should clear queue completely when processQueue() is called once', () => {

        queueService.enqueue(1);
        queueService.enqueue(2);
        queueService.enqueue(3);

        expect(queueService.queue.length).toBe(3);

        queueService.processQueue();

        // somehow wait for processQueue() to complete

        expect(queueService.queue.length).toBe(0);
    });
});

我的问题是第二个expect()始终失败并显示消息Expected 3 to be 0。我假设这是由于postNumber()没有等待返回的promise,因此在第二个expect()被调用时队列不为空。

在尝试断言队列已清空之前,如何等待processQueue()完成?

1 个答案:

答案 0 :(得分:0)

您应该修改processQueue以返回Promise。最简单的方法是使用async关键字标记方法,然后使用await

async processQueue(): Promise<void> 
{
    this.processingQueue = true; // we are currently processing a queue, so make sure setInterval does not trigger another processing run

    if (this.queue.length !== 0) 
    { // are there any numbers to deal with?
        const item = this.queue[0]; // get the first number in the queue

        try
        {
            await this.postNumber(item); // POST it (returns a promise)
            // if successful...
            this.queue.shift(); // we've dealt with this item, so remove it from the queue
            this.processQueue(); // check the queue again (recurses until all items have been dealt with)
        }
        catch
        {
                this.processingQueue = false; // something went wrong, so stop
        }
    } 
    else 
    {
        this.processingQueue = false; // queue is empty, stop processing
    }
}

然后在你的测试中:

it('should clear queue completely when processQueue() is called once', async (done) => {

    queueService.enqueue(1);
    queueService.enqueue(2);
    queueService.enqueue(3);

    expect(queueService.queue.length).toBe(3);

    await queueService.processQueue();

    // somehow wait for processQueue() to complete

    expect(queueService.queue.length).toBe(0);

    done();
});    

希望这有帮助。