vli*_*o20 1 javascript unit-testing decorator typescript jestjs
提前对漫长的探索表示歉意。我试图尽可能清楚地说明我面临的问题。
我创建了一个装饰器 utils 库,在使用其中一个装饰器时遇到了奇怪的行为(https://github.com/vlio20/utils-decorators/blob/master/src/after/after.ts)。
装饰器被命名为“after”,它应该在执行装饰方法后执行不同的函数。但事情是这样的,如果函数返回一个 Promise,装饰器应该等待它被解析,然后才调用 after func。
这是相关代码:
if (resolvedConfig.wait) {
const response = await originalMethod.apply(this, args);
afterFunc({
args,
response
});
} else {
const response = originalMethod.apply(this, args);
afterFunc({
args,
response
});
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我为装饰器提供了一个标志,以指示装饰方法是一个异步函数,并且它返回一个 Promise。我很乐意通过以下代码来阅读此标志:
const response = await originalMethod.apply(this, args);
afterFunc({
args,
response
});
Run Code Online (Sandbox Code Playgroud)
基本上,我希望始终放在await原始方法的执行之前,因为根据我的理解,在同步方法的情况下,等待不会执行任何操作。
问题是,当我按照上面的建议更改代码时,以下单元测试失败:
it('should verify after method invocation when method is provided', () => {
let counter = 0;
const afterFunc = jest.fn(() => {
expect(counter).toBe(1);
});
class T {
@after<T, void>({
func: afterFunc
})
foo(x: number): void {
return this.goo(x);
}
goo(x: number): void {
expect(counter++).toBe(0);
return;
}
}
const t = new T();
const spyGoo = jest.spyOn(T.prototype, 'goo');
t.foo(1);
expect(spyGoo).toBeCalledTimes(1);
expect(spyGoo).toBeCalledWith(1);
expect(afterFunc.mock.calls.length).toBe(1); // this line fails
});
Run Code Online (Sandbox Code Playgroud)
我创建了一个库的分支,其中这个确切的测试失败了(https://github.com/vlio20/utils-decorators/pull/new/after-issue)。
我的认知有什么问题吗?
基本上,我希望始终将等待放在原始方法的执行之前,因为根据我的理解,在同步方法的情况下,等待不会执行任何操作。
这不是真的。根据 MDN 上的 AsyncFunction 参考(其本身直接参考 ECMAScript 规范),任何表示为 的函数都async将始终使函数体在常规调用序列之外执行。
换句话说,被调用者对 async/await 函数并不重要,它始终会异步解析。这很重要,因为理想情况下,函数应该只同步或异步,而不能两者兼而有之。这被体现在异步函数的返回类型中:它们总是会产生一个 Promise,无论它们内部发生什么,并且 Promise 永远不能被同步检查。
实现此目的的唯一方法是完全避免使用await/async并直接检查函数的返回类型:
const after = ({ func }) => (f) => (..args) => {
const value = f(...args)
if ('then' in value === false) {
func()
return value
}
return value.then(value => {
func()
return value
})
}
Run Code Online (Sandbox Code Playgroud)
正如您可能从这个答案(以及我的参考文献)的语气中看出的那样,我认为这不是一个好的方法。建议保持函数完全同步或异步。
| 归档时间: |
|
| 查看次数: |
3043 次 |
| 最近记录: |