具有回调功能的模拟节点模块

时间:2020-06-16 15:48:51

标签: javascript unit-testing jestjs

我有一些代码以其回调形式使用节点模块ssh-exec

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回调?

1 个答案:

答案 0 :(得分:1)

简短的答案是您不要模拟回调,因为这是您要测试的主题的一部分。您当前的测试无效,因为ssh-exec 返回承诺;它接受并调用回调。通常,双打测试需要匹配其替换对象的接口。

相反,请使用模拟的ssh-exec来调用 real 回调:

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

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`;

  // you can't await here, because it will block until the callback is invoked...
  const promise = myCodeThatUsesSshExec(1, 2, 3);

  // assert on the call to ssh-exec
  expect(sshExec).toHaveBeenCalledWith('ls -lh', 'ubuntu@my-remote.com', expect.any(Function));

  // invoke the callback, which is the third argument to the first call
  sshExec.mock.calls[0][2](null, resp);

  // assert on the result
  expect(await promise).toEqual(['Dockerfile', 'app.js', 'bin', 'jest.config.js']);
  // or you can remove async from this test case and use:
  // expect(promise).resolves.toEqual(['Dockerfile', 'app.js', 'bin', 'jest.config.js']);
});

或者,为ssh-exec制作自己的包装,使其更适合您的用例:

const sshPromise = (...args) => new Promise((resolve, reject) => {
  sshExec(...args, (err, stdout, stderr) => {
    if (err) {
      reject(err);
    } else if (stderr) {
      reject(stderr);
    } else {
      resolve(stdout);
    }
  });
});

现在,您可以模拟自己拥有的这个更简单的界面,并且原始测试将按预期工作。

它还简化了使用代码:

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;
  });