javascript - sinon spy 不在生成器循环中注册调用?

标签 javascript node.js mocha.js generator sinon

我想检查一段代码是否正在被调用,所以我使用 sinon spy 来断言这一点。然而,尽管 console.logs 显示代码已被正确调用,但 spy 程序似乎失败了。

我想知道我的函数作为生成器是否导致我的 spy 误报它正在做什么。

我的代码(为了简洁起见,我删除了一些 block ):

  isBlacklisted(release, jobUUID) {

    names.forEach((name) => {
      this._spawnPythonProcessGenerator(
        this.IS_BLACKLISTED_SCRIPT,
        name
      ).next().value
        .then((data) => {
          console.log(data);
        })
        .catch((err) => {
          this._errorEvent(release, name, err, jobUUID);
        });
    }, this);
  }

  _errorEvent(release, name, err, jobUUID) {
    console.log('got here');
  }

  *_spawnPythonProcessGenerator(scriptSrc, name) {
    const pythonProcess = this._childProcess.spawn(
      'python3',
      [...arguments]
    );
    yield new Promise((resolve, reject) => {
      pythonProcess.stderr.on('data', (err) => {
        reject(err.toString());
      });

      pythonProcess.stdout.on('data', (data) => {
        resolve(data.toString());
      });
    });
  }

和我的测试:

const Blacklist = require('../../src/Blacklist2');
const childProcess = require('child_process');
const uuid = require('uuid/v4');

describe('Blacklist', () => {
  let blacklist;
  beforeEach(() => {
    blacklist = new Blacklist(childProcess);
    blacklist.IS_BLACKLISTED_SCRIPT = './test/helpers/good.py';
  });
  describe('isBlacklisted', () => {
    it('should call the _errorEvent for every name in a release when the blacklist application is not available', async () => {
      let release = {
        id: 1001,
        asset_controller: {
          id: 54321,
        },
        display_name: 'Blah',
        names: [
          {
            id: 2001,
            name: 'Blah',
          },
        ],
      };

      blacklist.IS_BLACKLISTED_SCRIPT = './test/helpers/'+ uuid() +'.py';


      const spy = sinon.spy(blacklist, '_errorEvent');
      blacklist.isBlacklisted(release, uuid());

      console.log(spy);
      sinon.assert.calledTwice(spy);
      spy.restore();
    });
  });
});

我的 spy 报告:

notCalled: true

最佳答案

我会将我的评论扩展为实际答案,希望有所帮助。

您的问题在于异步,而不在于生成器。您需要 isBlacklisted 来返回您可以等待的 promise 。否则你的断言会在 spy 被调用之前发生。

类似这样的事情:

isBlacklisted(release, jobUUID) {
    let promises = names.map((name) => {
      return this._spawnPythonProcessGenerator(
        this.IS_BLACKLISTED_SCRIPT,
        name
      ).next().value
        .then((data) => {
          console.log(data);
        })
        .catch((err) => {
          this._errorEvent(release, name, err, jobUUID);
        });
    }, this);

    return Promise.all(promises);
}

然后,在您的测试中:

return blacklist.isBlacklisted(release, uuid())
    .then(() => {
        sinon.assert.calledTwice(spy);
    });

另外...这与您的问题无关,但您的 _spawnPythonProcessGenerator 方法不需要是生成器。您只需通过像这样调用 next 并为每个数组项再次调用整个过程来使用它的第一个值。

如果你取出*,将yield更改为return,并跳过.next( ).value 当你调用它时。您可能还想重命名它,因为它不是生成器。

_spawnPythonProcess(scriptSrc, name) {
    const pythonProcess = this._childProcess.spawn(
      'python3',
      [...arguments]
    );
    return new Promise((resolve, reject) => {
      pythonProcess.stderr.on('data', (err) => {
        reject(err.toString());
      });

      pythonProcess.stdout.on('data', (data) => {
        resolve(data.toString());
      });
    });
}

当你调用它时:

let promises = names.map((name) => {
  return this._spawnPythonProcess(
    this.IS_BLACKLISTED_SCRIPT,
    name
  )
    .then((data) => {
      console.log(data);
    })
    .catch((err) => {
      this._errorEvent(release, name, err, jobUUID);
    });
}, this);

return Promise.all(promises);

关于javascript - sinon spy 不在生成器循环中注册调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53724283/

相关文章:

javascript - 用于日期验证的正则表达式 - 解释

javascript - 来自对象的特定子对象

javascript - ignore 参数在 gulp 和 nodemon 中如何工作?

node.js - seneca和redis有什么关系

node.js - Sinon stub 链接方法

gruntjs - 如何使用 Mocha 作为分层测试套件?

javascript - 使用javascript将值动态插入数组

javascript - 单击时隐藏下拉菜单项?

node.js - 保护 nodeJS 数据库配置文件

unit-testing - 单元测试 : mock document used by an imported TypeScript dependency?