Javascript 带有回调函数的模拟节点模块

Javascript 带有回调函数的模拟节点模块,javascript,unit-testing,jestjs,Javascript,Unit Testing,Jestjs,我有一些代码在回调形式中使用节点模块 const sshExec = require('ssh-exec'); const myCodeThatUsesSshExec = (arg1,arg2,arg3) => new Promise((resolve, reject) => { sshExec('ls -lh', 'ubuntu@my-remote.com', function (err, stdout, stderr) { if(err) { reject(er

我有一些代码在回调形式中使用节点模块

const sshExec = require('ssh-exec');

const myCodeThatUsesSshExec = (arg1,arg2,arg3) => new Promise((resolve, reject) => {
  sshExec('ls -lh', 'ubuntu@my-remote.com', function (err, stdout, stderr) {
  if(err) {
    reject(err);
  } else if(stderr) {
    reject(stderr);
  } else {
   // process stdout
   const results = process stdout into an array...
   resolve(results);
  }
})
});
我试图测试我的代码,但我不知道如何模拟回调函数来返回模拟数据。这是我迄今为止的尝试-

const myCodeThatUsesSshExec = require('./my-code');
jest.mock('ssh-exec');

test('ssh test', async () => {
    const resp = `total 268K
-rw-rw-rw- 1 bob bob 369 Jun 12 15:00 Dockerfile
-rw-rw-rw- 1 bob bob 849 Jun 12 14:46 app.js
drwxr-xr-x 1 bob bob 4.0K Jun 12 10:01 bin
-rw-rw-rw- 1 bob bob 49 Jun 15 14:34 jest.config.js`;

  // I know this doesn't work, just trying to illustrate what I'm trying to do.
    sshExec.mockReturnValue(Promise.resolve(resp));

  const received = await myCodeThatUsesSshExec(1,2,3);
  expect(received).toEqual(['Dockerfile', 'app.js', 'bin', 'jest.config.js']);

});

如何模拟ssh exec回调?

简短的回答是,您不模拟回调,因为这是您试图测试的主题的一部分。您当前的测试不起作用,因为ssh exec没有返回承诺;它接受并调用回调。通常,双重测试需要匹配它们所替换的东西的接口

相反,使用模拟的ssh exec调用真正的回调:

const sshExec=需要'ssh-exec'; const myCodeThatUsesSshExec=require'/my code'; 开玩笑,模仿‘ssh-exec’; 测试“ssh测试”,异步=>{ const resp=`总计268K -rw rw rw-1鲍勃369年6月12日15:00码头文件 -rw rw rw rw-1 bob bob 849 Jun 12 14:46 app.js drwxr-xr-x 1 bob bob 4.0K Jun 12 10:01 bin -rw rw rw-1 bob bob 49 Jun 15 14:34 jest.config.js`; //您不能在这里等待,因为它将阻塞,直到调用回调。。。 const promise=myCodeThatUsesSshExec1,2,3; //在调用ssh exec时断言 期望Hexec.已与“ls-lh”一起调用ubuntu@my-remote.com',expect.anyFunction; //调用回调,这是第一个调用的第三个参数 sshExec.mock.calls[0][2]分别为null; //断言结果 toEqual['Dockerfile','app.js','bin','jest.config.js']; //或者,您可以从此测试用例中删除async并使用: //expectpromise.resolves.toEqual['Dockerfile','app.js','bin','jest.config.js']; }; 或者,为ssh exec制作与您的用例更匹配的包装:

const sshPromise=…args=>newpromiseresolve,reject=>{ sshExec…args,err,stdout,stderr=>{ 如果出错{ 拒绝者; }如果是标准的话{ 拒绝者; }否则{ 解决方案; } }; }; 现在您可以模拟这个您拥有的更简单的接口,并且您的原始测试将按预期工作

它还简化了消费代码:

const myCodeThatUsesSshExec = (arg1, arg2, arg3) => sshPromise('ls -lh', 'ubuntu@my-remote.com')
  .then((stdout) => {
    // process stdout
    const results = process stdout into an array...
    return results;
  });

该测试与您使用exec的方式完全不一致-主题实际上不会返回任何内容。如果您在模拟exec,您需要考虑如何测试它,以获得正确的参数,包括回调。练习回调将意味着输出到console.log,如图所示,而不是返回一个要断言的值。@JornSharpe现在看一看,原始版本只是他们文档中的一个示例,用于说明使用API的回调形式。这很好,我非常喜欢第二个版本,但是我不想测试ssh承诺吗?@user210757是的,您确实想测试该外观,但不是在单元级别。细节取决于更大的上下文,但例如,使用已知测试目录的集成测试将允许您检查总体结果是否正确。在本例中,模仿您不拥有的ssh exec的危险在于,如果接口或行为发生变化,您可能要等到太晚才能发现,因为模仿仍然可以正常工作。