在单元测试中使用 AudioContext
Posted
技术标签:
【中文标题】在单元测试中使用 AudioContext【英文标题】:Using AudioContext in unit tests 【发布时间】:2019-12-14 17:53:53 【问题描述】:我正在开发一个 javascript 库 (https://github.com/yvesgurcan/web-midi-player) 以在 Web 应用程序中启用 MIDI 播放。该库依赖于 Web Audio API 来创建播放这些 MIDI 文件的方法 (https://github.com/yvesgurcan/web-midi-player/blob/test/src/MidiPlayer.js#L50)。但是,我无法使用 Jest (https://github.com/yvesgurcan/web-midi-player/blob/test/tests/midiPlayer.js) 创建有意义的单元测试,因为这些测试无法访问 window
对象,尤其是 window.AudioContext
。因此,运行依赖于 AudioContext
的应用程序代码会引发与该对象不存在相关的错误,并且我实际上无法在库中测试很多东西。
我尝试了以下软件包来解决我的问题:jsdom
、jsdom-global
和 web-audio-test-api
,但这些软件包似乎都没有在环境中注入 AudioContext
。
我认为这里的解决方案是 stub/mock AudioContext
,但这对于可靠的单元测试来说听起来不是一个好的解决方案。
你们对测试 Web Audio API 有什么建议?存根是这里唯一可行的解决方案吗?
【问题讨论】:
【参考方案1】:我认为这在一定程度上取决于您要测试的内容。由于您使用的是 Jest,我想您只是对测试自己代码的正确性感兴趣。在这种情况下,我建议完全模拟 Web Audio API。这不是您的责任,您可以假设它按应有的方式工作。您唯一需要测试的是您的代码是否进行了预期的调用。
像 AudioContext 构造函数这样模拟全局可用变量总是有点棘手,但您可以允许将 AudioContext 作为可选参数传递到您的 MidiPlayer
类中。这将使测试更容易一些,并且还允许您库的用户带来他们自己的 AudioContext。
我想到了这样的事情:
class MidiPlayer
constructor(
// ... the other options ...
context = new AudioContext()
)
// ...
在测试中,您可以简单地用假的AudioContext
实例化MidiPlayer
。
const fakeAudioContext =
currentTime: 3,
// ... and all the other things your code uses ...
;
const midiPlayer = new MidiPlayer( context: fakeAudioContext );
我最近回复了similar question related to Tone.js,这可能会有所帮助。基本思路是一样的。
如果您想测试您的库是否可以在浏览器中与 Web Audio API 很好地配合使用,我建议您使用像 Karma 这样的测试运行器。它在真实浏览器中执行测试,因此可以使用所有浏览器 API。
【讨论】:
谢谢你,克里斯。我之前在 Tone.js 上看到过这个问题,但没想到对AudioContext
做同样的事情!我非常喜欢同时提供使用现有AudioContext
的选项并为MidiPlayer
实例提供存根的想法。听起来这将允许库的用户可能扩展 web-midi-player
中尚未实现的功能 - 例如控制音频的音量。我是否正确假设这一点?这样做是否有可能的缺点和其他好处?非常感谢您的专业知识!
我认为目前真的不可能使用您的MidiPlayer
并将一些效果附加到信号链,因为它目前直接连接到AudioContext
的destination
。 github.com/yvesgurcan/web-midi-player/blob/test/src/… 但是您也可以选择允许人们指定他们自己的目的地。这有意义吗?
我对 Web Audio API 还不是很了解,但我从这个项目中学到了很多东西。让人们指定他们自己的目的地对我来说很有意义(例如如何在 MidiPlayer 中实现),但我不确定我是否理解信号链的附加效果会做什么,因为我不确定什么效果和信号链是.我的意思是,我有想法,但我不确定:)
例如,您可以在应用程序的某处有一个 AudioContext。然后你可以创建一个 GainNode 作为目的地并像这样实例化一个 MidiPlayer:new MidiPlayer( context: myAudioContext, destination: myGainNode )
。然后可以在将myGainNode
连接到 AudioContext 的destination
之前添加一个 EQ。 const filter = myAudioContext.createBiquadFilter(); myGainNode.connect(filter).connect(myAudioContext.destination);
以上是关于在单元测试中使用 AudioContext的主要内容,如果未能解决你的问题,请参考以下文章
Java应用XVIII在 Java 中使用JUnit5进行单元测试和自动化测试
在 VS 中运行单元测试与调试单元测试时,我应该期待啥区别?
Request.GetOwinContext 在单元测试中返回 null - 如何在单元测试中测试 OWIN 身份验证?