在单元测试中使用 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 的应用程序代码会引发与该对象不存在相关的错误,并且我实际上无法在库中测试很多东西。

我尝试了以下软件包来解决我的问题:jsdomjsdom-globalweb-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 并将一些效果附加到信号链,因为它目前直接连接到AudioContextdestination。 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的主要内容,如果未能解决你的问题,请参考以下文章

Android怎样进行单元测试

Java应用XVIII在 Java 中使用JUnit5进行单元测试和自动化测试

在AndroidStudio中使用单元测试

在 VS 中运行单元测试与调试单元测试时,我应该期待啥区别?

单元测试

Request.GetOwinContext 在单元测试中返回 null - 如何在单元测试中测试 OWIN 身份验证?