jest跳出了有希望的功能

时间:2017-10-31 14:28:55

标签: javascript jestjs

我试图测试一个调用另一个模块函数的函数,该函数返回一个promise, 问题是,jest不会等待完成myFunction并跳出它并将其视为一个承诺,因为结果部分显示了"完成"在"解决"之前打印消息信息。我一直在使用setImmediate,但我宁愿不使用它,也想了解原因。

代码的简化版本如下:

被模拟的模块

// repo.js
const getItems = () => {
    console.log('real');
    return  new Promise((resolve, reject) => {
            setTimeout(
                () => resolve('result'), 1000);
        }
    );
}
module.exports = {
    getItems
};

被测单位:

 // sample.js
const repo = require('./repo');

const myFunction = (req, res) => {
    console.log('myFunction');

    repo.getItems()
        .then(goals => {
            console.log('resolve');
            res.val = 'OK';
        }).catch(err => {
        console.log('reject');
        res.val = 'Failed';
    });

    return;
};

module.exports = {myFunction};

测试文件:

// sample.test.js
const repo = require('./repo');
const sample = require('./sample');

const result = {
    'message': 'done'
};
describe('Tests for receiving items', () => {
        it('should call and be successful. ', () => {
            repo.getItems = jest.fn(() => {
                console.log('mocking');
                return new Promise((resolve) => ( resolve(result) ));
            });
            const response = {val: 'test'};
            const request = {};
            sample.myFunction(request, response);
            console.log('done');
            expect(response.val).toBe('OK');
        })
    }
);

结果是:

  console.log MySample\sample.js:5
    myFunction

  console.log MySample\sampel.test.js:11
    mocking

  console.log MySample\sampel.test.js:17
    done

  console.log MySample\sample.js:9
    resolve


Error: expect(received).toBe(expected)

Expected value to be (using ===):
  "OK"
Received:
  "test"
Expected :OK
Actual   :test

1 个答案:

答案 0 :(得分:-1)

您编写的测试反映了正确的用法,您可能会说它完成了它的目的,因为它在您的实现中发现了一个错误。

为了表明究竟出了什么问题,我将摆​​脱一切不需要的东西,这将导致一个更小的例子。 Jest可以运行以下测试文件,它会重现您的问题。

const myFunction = (res) => {
    Promise.resolve()
        .then(goals => {
            res.val = 'OK';
        }).catch(err => {
            res.val = 'Failed';
        });

    return;
};

it('should call and be successful. ', () => {
    const response = {val: 'test'};
    myFunction(response);
    expect(response.val).toBe('OK');
})

myFunction启动一个promise(在此处立即解析,没有任何值)并且不返回任何内容(undefined)。您还可以使用Promise.reject代替Promise.resolve来测试错误部分。当您致电myFunction(response)时,myFunction完成时会执行下一行。这不是承诺实际完成的时候,而是功能本身。承诺可能需要花费任何时间,而且无法告诉它何时实际完成。

为了能够知道承诺何时完成,您需要将其返回,因此您可以使用.then()在承诺解决后执行.then().catch()都会返回一个新的承诺,该承诺会使用返回的值进行解析,在这种情况下,该值又是undefined。这意味着您需要在.then()回调中进行断言。类似地,Jest认为测试在退出函数时结束,即使它应该等待承诺得到解决。为此,您可以从测试中返回承诺,Jest将等待其完成。

const myFunction = (res) => {
    // Return the promise from the function, so whoever calls myFunction can
    // wait for the promise to finish.
    return Promise.resolve()
        .then(goals => {
            res.val = 'OK';
        }).catch(err => {
            res.val = 'Failed';
        });
};

it('should call and be successful. ', () => {
    const response = {val: 'test'};
    // Return the promise, so Jest waits for its completion.
    return myFunction(response).then(() => {
        expect(response.val).toBe('OK');
    });
})

您也可以使用async / await,但请记住,您仍然需要了解promises的工作方式,因为它使用了下面的promises。 async函数总是返回一个promise,因此Jest知道等待它的完成。

it('async/await version', async () => {
    const response = {val: 'test'};
    // Wait for the promise to finish
    await myFunction(response);
    expect(response.val).toBe('OK');
})

通常你也会从promise(.then().catch())返回一个值,而不是改变外部变量(res)。因为如果你对多个promises使用相同的res,你将有一个数据竞争,结果取决于首先完成的promises,除非你按顺序运行它们。