如何在玩笑测试中模拟“readline.createInterface”

Posted

技术标签:

【中文标题】如何在玩笑测试中模拟“readline.createInterface”【英文标题】:How to mock 'readline.createInterface' in jest tests 【发布时间】:2022-01-21 09:26:23 【问题描述】:

我需要测试“readline.createInterface”。

下面是我需要测试的代码:

private createReadStreamSafe(filePath: string): Promise<fs.ReadStream> 
        return new Promise((resolve, reject) => 
          const fileStream = fs.createReadStream(filePath)
          console.log('file Stream')
          fileStream
            .on('error', () => 
              reject('create read stream error')
            )
            .on('open', () => 
              resolve(fileStream)
            )
        )
      
    
      async start() 
        const fileStream = await this.createReadStreamSafe(this.filePath)
    
        const rl = readline.createInterface(
          input: fileStream,
          output: process.stdout,
          terminal: false
        )
    
        for await (const line of rl) 
          ...
        
      

我尝试了以下代码:

it('should work', async () => 
    const mockedReadStream = new Readable()
    jest.spyOn(fs, 'createReadStream').mockReturnValue(mockedReadStream as any)
    jest.spyOn(readline, 'createInterface').mockImplementation(() => 
      const lines = ['text', 'text2', 'text3']

      return 
        [Symbol.asyncIterator]() 
          return 
            i: 0,
            next: () => 
              if (this.i < 3) 
                return Promise.resolve( value: lines[this.i++], done: false )
              

              return Promise.resolve( done: true )
            
          
        
       as any
    )

    const app = new App('myFile.txt')

    let promise = app.start()
    mockedReadStream.emit('open')
    await expect(promise).resolves.toBe(undefined)
  )

但以下代码永远无法到达

for await (const line of rl) 
...
        

有没有办法模拟 readline.createInterface 然后它与 for await (const line of rl) 一起工作?

【问题讨论】:

【参考方案1】:

问题是:测试期间没有触发异步可迭代对象。

解决方案,我们可以在 mock 中使用一个数组,像这样:

jest.spyOn(readline, 'createInterface').mockImplementationOnce(() => 
      return ['text1', 'text2'] as any
    )

因为等待(可迭代的常量项)适用于异步可迭代对象以及同步可迭代对象。使用同步迭代,它们将自动执行。

【讨论】:

以上是关于如何在玩笑测试中模拟“readline.createInterface”的主要内容,如果未能解决你的问题,请参考以下文章

用玩笑进行单元测试时,如何以角度模拟 ResizeObserver polyfill?

如何开玩笑地模拟 VueAxios

如何在玩笑中模拟/监视 useState 钩子?

在“if”语句中没有调用模拟函数 - 用玩笑和酶反应应用程序测试?

开玩笑地模拟 useDispatch 并在功能组件中使用该调度操作来测试参数

开玩笑:当第三方库使用控制台时如何模拟控制台?