Javascript 玩笑带着承诺跳出了功能
我试图测试一个函数,它调用另一个模块的函数,该函数返回一个承诺, 问题在于jest并不等待myFunction完成,而是跳出myFunction并将其视为承诺,因为结果部分显示“完成”消息在“解决”消息之前打印。我一直在使用它,但我不想使用它,我想了解原因 代码的简化版本如下: 模拟的模块Javascript 玩笑带着承诺跳出了功能,javascript,jestjs,Javascript,Jestjs,我试图测试一个函数,它调用另一个模块的函数,该函数返回一个承诺, 问题在于jest并不等待myFunction完成,而是跳出myFunction并将其视为承诺,因为结果部分显示“完成”消息在“解决”消息之前打印。我一直在使用它,但我不想使用它,我想了解原因 代码的简化版本如下: 模拟的模块 // repo.js const getItems = () => { console.log('real'); return new Promise((resolve, reject
// 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
您编写的测试反映了正确的用法,您可以说它实现了它的目的,因为它在您的实现中发现了一个bug 为了说明到底哪里出了问题,我将去掉所有不需要的东西,这将引出一个更简单的例子。下面的测试文件可以由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()
都返回一个新的promise,该promise使用返回的值进行解析,在本例中,该值也是未定义的。这意味着您需要在.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');
});
})
it('async/await version', async () => {
const response = {val: 'test'};
// Wait for the promise to finish
await myFunction(response);
expect(response.val).toBe('OK');
})
您也可以使用async
/await
,但请记住,您仍然需要了解承诺是如何工作的,因为它在下面使用承诺。async
函数总是返回一个承诺,因此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');
});
})
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
)。因为如果您对多个承诺使用相同的res
,您将面临一场数据竞赛,结果取决于哪些承诺首先完成,除非您按顺序运行它们。首先,我应该说,使用此代码的实际应用程序运行得非常好,问题在于使用jest进行测试。我无法从函数返回承诺,调用方不希望返回值。我只允许修改对象状态。调用方是第三方代码,因此我无法更改调用方。您呈现代码的方式与我的代码不同。myFunction不返回任何内容,因为调用方希望myFunction在结束前进行修改,并且只查看传递给myFunction的对象。“调用方希望myFunction在结束前进行修改”,这意味着您不能执行任何异步操作,因为它们是非阻塞的,并且函数总是在异步任务完成之前结束。如果您不返回承诺或接受继续回调,那么无论用户是在异步任务完成之前还是之后读取该值都是纯粹的运气。仅仅因为它在您的案例中恰好起作用(可能您在阅读之前做了一些工作),并不意味着它总是起作用,正如测试所示,如果用户这样使用它,它将失败。