【问题标题】:How do I stub a module method's callback with sinon?如何使用 sinon 存根模块方法的回调?
【发布时间】:2020-07-23 05:59:27
【问题描述】:

我正在使用 mv 模块来移动文件,这是一个较旧的模块,它仍然获得大量下载,并且有助于处理 docker 卷之间以及 docker 之外的文件移动。我创建了一个将 mv 方法视为承诺的方法。

在进行单元测试时,在方法中使用时我很难模拟 mv。

import mv from 'mv';

export class CmdUtils {
  /**
   * Move a file to a new location. Using mv, this will attempt a mv command, however
   * this could fail with docker volumes and will fallback to the mv module streaming
   * data to the new location as needed.
   * @param filePath - Full path to file
   * @param destinationFilePath - Full path to file's new destination
   */
  public static moveFile = (filePath: string, destinationFilePath: string): Promise<void> => {
    return new Promise((resolve, reject) => {
      mv(filePath, destinationFilePath, err => {
        if (!err) {
          resolve();
        } else {
          console.error('moveFile err', err);
          reject(err);
        }
      });
    });
  }
}

这是一个有差距的开始测试:

import mv from 'mv';
import { CmdUtils } from './cmd-utils';

describe("CmdUtils: moveFile", () => {
  it("should successfully move a file using mv module", async () => {
    const sandbox = sinon.createSandbox();
    try {
      const moveFromPath = '/full/path/to/file.jpg';
      const moveToPath = '/full/path/to/destination/file.jpg';

      // Starting attempt at a replacement callback
      const mvCallback = (err: Error) => {
        if (!err) {
          Promise.resolve();
        } else {
          console.error('moveFile err', err.message);
          Promise.reject(err);
        }
      }

      // Stub mv
      sandbox.stub(mv)
      // What am I missing here?

      // Move file
      await CmdUtils.moveFile(moveFromPath, moveToPath);

      // expect no errors... (will revisit this)
    } finally {
      sandbox.restore();
    }
  });
});

如何模拟成功的文件移动?我看到了类似的问题,但还没有找到答案。

【问题讨论】:

  • moveFile 的设置方式不允许将 cb 存根到 mv。您没有将回调作为参数传递,因此无法将其存根以在mv 中使用它。似乎您需要重新处理 moveFile 才能访问回调并将其传递给 mv 以执行。
  • 感谢您的反馈@AndrewNolan。随着咖啡的吸收,我在想真正的问题是如何对包含 mv 的方法进行单元测试?我并不担心 mv 在做什么,只是 moveFile() 方法的行为应该如此。当我扩展单元测试能力时,请告诉我这是否有意义。
  • 我的咖啡也刚刚开始 :D 。要实现存根,请提取应用于mv 的回调并将其作为命名参数传递给moveFile。然后该命名参数作为回调传递给mv。然后你可以检查它的回调行为与resolvereject。我稍后会输入一个“答案”。
  • 复制。我想知道出于功能的目的,我是否应该传入一个命名参数以使单元测试工作,例如moveFile('orig.jpg', 'new.jpg', someCallbackIDontCareAbout)。使用 moveFile() 时我唯一关心的是将文件成功移动为承诺。

标签: node.js typescript mocha.js chai sinon


【解决方案1】:
class CmdUtil {
  static moveFileCb(resolve, reject, err) {
    if (!err) {
      resolve('RESOLVED');
    } else {
      reject(err);
    }
  }

  static moveFile() {
    return new Promise((resolve, reject) => {
      mv('test', 'test', CmdUtil.moveFileCb.bind(this, resolve, reject))
    })
  }
}

那么测试可能类似于你现在存根moveFileCb 的地方。使用该存根,您可以检查/断言回调的调用方式、调用次数等。

旁注:我没有使用bind 编写测试。这可能会给解决方案带来麻烦。

【讨论】:

  • 感谢您的回答。我会在下一次休息时跟进/尝试一下。
  • 最后,我最终使用了内置的 Promisify 来减少行数并从测试中省略,因为我有 90% 以上的覆盖率,涵盖了我可以控制的东西,包括使用这个的方法(他们可以处理错误)。
猜你喜欢
  • 2021-09-24
  • 2016-02-18
  • 1970-01-01
  • 2014-07-17
  • 2014-07-12
  • 2021-01-21
  • 2015-04-18
  • 2018-06-15
  • 2021-06-10
相关资源
最近更新 更多