Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/457.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 异步函数的行为与我对Jest的预期不同_Javascript_Asynchronous_Jestjs - Fatal编程技术网

Javascript 异步函数的行为与我对Jest的预期不同

Javascript 异步函数的行为与我对Jest的预期不同,javascript,asynchronous,jestjs,Javascript,Asynchronous,Jestjs,Javascript Jest测试框架说,我需要在回调中添加done(),以测试异步函数,否则函数将在测试完成后返回,因此测试将失败。我已将Jest添加到我的package.json中,并添加了以下两个文件: src.js: function fetchData(cb) { setTimeout(cb, 2000, 'peanut butter') } module.exports = fetchData function fetchData(cb) { setTimeout(cb,

Javascript Jest测试框架说,我需要在回调中添加
done()
,以测试异步函数,否则函数将在测试完成后返回,因此测试将失败。我已将Jest添加到我的package.json中,并添加了以下两个文件:

src.js:

function fetchData(cb) {
  setTimeout(cb, 2000, 'peanut butter')
}

module.exports = fetchData
function fetchData(cb) {
  setTimeout(cb, 2000, 'peanut')
}

module.exports = fetchData
src.test.js:

const fetchData = require('./src')

test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter')
    // no done() method!
  }

  fetchData(callback);
})
const fetchData = require('./src')

test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter')
    done()
  }

  fetchData(callback);
})
我用上面的代码通过了测试,但我认为我应该得到一个失败的测试,因为我的测试文件中没有
done()
。我的
fetchData()
方法不是异步的吗


编辑:根据尼古拉斯的回答,我将代码更改为:

src.js:

function fetchData(cb) {
  setTimeout(cb, 2000, 'peanut butter')
}

module.exports = fetchData
function fetchData(cb) {
  setTimeout(cb, 2000, 'peanut')
}

module.exports = fetchData
src.test.js:

const fetchData = require('./src')

test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter')
    // no done() method!
  }

  fetchData(callback);
})
const fetchData = require('./src')

test('the data is peanut butter', () => {
  function callback(data) {
    expect(data).toBe('peanut butter')
    done()
  }

  fetchData(callback);
})
测试运行者应根据Jest文档评估期望/断言,并失败(花生酱通过,花生酱预期),但仍显示通过测试

此外,Jest文档还指出:

If done() is never called, the test will fail, which is what you want to happen

测试通过回调中有和没有
done()
方法,以及有和没有传递给回调的正确(
花生酱
)参数(即,所有四个变量都通过)。

如果没有作为参数传递
done
,测试运行程序认为代码是同步的,不会等待特殊的事情发生——在本例中,调用
done


因此,在您的断言/期望有机会运行之前,测试被标记为成功。

您的
fetchData
本身是异步的,Jest对此没有影响。另一方面,Jest需要知道测试何时完成,通常是测试函数退出的时候,但这只包括同步代码。在您的例子中,当您的测试函数退出时,您没有调用任何断言,Jest认为这是成功的(因为没有失败)

为了证明没有调用断言,我将使用仅当它完全调用
number
断言时才通过测试。例如,如果在示例中将其设置为1:

test('the data is peanut butter', () => {
  // Require exactly 1 assertion to pass the test
  expect.assertions(1)

  function callback(data) {
    expect(data).toBe('peanut butter')
  }

  fetchData(callback)
})
您将看到错误消息:

● the data is peanut butter

  expect.assertions(1)

  Expected one assertion to be called but received zero assertion calls.
如您所见,没有调用断言。除了演示目的之外,您还可以使用
expect.assertions
来确保在未调用断言时测试失败

对于任何异步任务,都需要让Jest知道测试是异步的,并且需要在测试完成时通知Jest。一种方法是使用
done
回调。当您的测试函数接受一个参数(通常称为
done
)时,Jest会将其视为异步测试,并等待您调用
done()
回调,或者当达到超时阈值时(默认值:5s)。在已编辑的示例中,函数接受零参数,对
done()
的调用不是Jest的回调

test('done callback', done => {
  //                  ^^^^ 1 argument
  // Jest waits until this callback is called or the timeout was reached.
  // ...
})

test('no callback argument', () => {
  //                         ^^ no argument
  // Test finishes as soon as the function exits
  // ...
})
这已经很少使用了,因为现在承诺更为常见,而且它们使这变得更为简单,因为您可以返回承诺,而Jest将等待其完成,而无需任何额外设置。此外,您还可以使用
async
await
使其更加完善,因为它是承诺之上的语法糖


另请参见和

如果未将
done
作为参数传递,则代码将被视为同步且不等待。在断言有机会运行之前,测试被认为是成功的。无论我设置了多长时间的计时器,测试运行者都会等待计时器完成,然后在控制台中报告测试结果。但是文档说我需要做一些特殊的事情来处理异步代码,而且Expection对象肯定是异步执行的(作为对
setTimeout()
的回调),测试运行程序(或者更具体地说是节点本身)在终止进程之前等待最后注册的
setTimeout
回调过期。尝试创建一个空文件,只在其中放入一个
setTimeout
。您将看到,它将不会退出进程,直到FiresTest有一个总的gotcha,在那里它修改了计时函数的行为。我对我的答案进行了编辑,以包括一个工作示例和对讨论该行为的问题的引用。同样,在您包含的编辑中,您没有将
done
作为参数传递给
test
<代码>完成除了在完成测试时被调用外,还应作为参数传递。看看我的例子,运行它,你就会明白重点。请注意第8行,其中我通过了
test
作为一个参数,如果您通过但未调用
done
测试,则测试应在一段时间后超时。在我使用的Mocha中,如果未调用
done
,则默认情况下2000毫秒后超时。在我的书中,编写这些本机函数是一个很大的禁忌。他们本可以创建自己的计时功能,这样可以避免一半的问题和我们的时间。至于
done从不被调用,如果测试失败
,这只适用于您实际通过
if done
作为参数的情况,而您在任何示例中都没有这样做。希望helpsJest在默认情况下不会覆盖计时器,但它提供了
jest.useFakeTimers()
来模拟计时器进行手动(细粒度)控制。请参见。在我的示例中,
setTimeout
是如何来的呢?它直接在规范文件中声明的,除非我使用
useFakeTimers()
/
runAllTimers()
?@NicholasKyriakides在您的示例中,
expect(data).toBe('foo-butter')
断言失败,从而抛出
done()
未到达第行。正是因为Jest不会劫持
setTimeout
(除非您使用
Jest.uesFakeTimers
),所以它不知道它抛出了什么。解决方法如中所示。承诺不会出现此问题,因为如果断言抛出
。然后
,回调,承诺将被拒绝,并指示失败