如何在Jest中模拟嵌套函数? [英] How to mock nested function in Jest?

查看:99
本文介绍了如何在Jest中模拟嵌套函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到此错误

Cannot find module 'httpsGet' from 'functions/getSecureString.test.js'

httpsGet()是我自己的函数,位于getSecureString.js的按钮上,并由getSecureString()调用. httpsGet()使用https模块从需要客户端证书的网站获取内容.

httpsGet() is my own function, and is at the button of getSecureString.js, and called by getSecureString(). httpsGet() uses the https module to get content from a website that requires client side certificates.

我正在尝试模拟httpsGet(),我猜我遇到的问题是因为它不包含在require()中,因此jest.mock('httpsGet')失败了.

I am trying to mock httpsGet() and I am guessing the problem I have is because it isn't included with require() and hence jest.mock('httpsGet') fails.

任何人都可以弄清楚是否是这种情况,我应该如何解决?

Can anyone figure out if that is the case, and how I should fix it?

在线示例,网址为: https://repl.it/@SandraSchlichti/jest-playground -4

getSecureString.test.js

const getStatusCode = require('./getSectureString');
jest.mock('httpsGet');

describe("getSecureString ", () => {
  describe('when httpsGet returns expected statusCode and body includes expected string', () => {
    let result;
    beforeAll(async () => {
      httpsGet.mockResolvedValue({
        statusCode: 200,
        body: 'xyz secret_string xyz'
      })
      result = await getSecureString({
        hostname:   'encrypted.google.com',
        path:       '/',
        string:     'secret_string',
        statusCode: 200,
        aftaleId:   1234,
        certFile:   1234,
        keyFile:    1234,
        timeout:    1000,
      })
    });

    it('should return 1', () => {
      expect(result).toEqual(1)
    })
  });

  describe('when httpsGet returns expected statusCode and body includes expected string', () => {
    let result;
    beforeAll(async () => {
      httpsGet.mockResolvedValue({
        statusCode: 200,
        body: 'xyz secret_string xyz'
      })
      result = await getSecureString({
        hostname:   'encrypted.google.com',
        path:       '/',
        string:     'not_secret_string',
        statusCode: 201,
        aftaleId:   1234,
        certFile:   1234,
        keyFile:    1234,
        timeout:    1000,
      })
    });

    it('should return 0', () => {
      expect(result).toEqual(0)
    })
  });

  describe("when an exception is thrown", () => {
    let result;
    beforeAll(async () => {
      // mockRejected value returns rejected promise
      // which will be handled by the try/catch
      httpsGet.mockRejectedValue({
        statusCode: 200,
        body: 'xyz secret_string xyz'
      })
      result = await getSecureString();
    })

    it('should return -1', () => {
      expect(result).toEqual(-1)
    })
  });

});

getSecureString.js

const fs = require('fs');
const https = require('https');
var uuid = require('uuid');
const {v4: uuidv4} = require('uuid');

module.exports = async function getSecureString(options) {
  options            = options || {};
  options.hostname   = options.hostname || {};
  options.path       = options.path || '/';
  options.string     = options.string || {};
  options.statusCode = options.statusCode || {};
  options.aftaleId   = options.aftaleId || {};
  options.certFile   = options.certFile || {};
  options.keyFile    = options.keyFile || {};
  options.timeout    = options.timeout || 0;

  const opt = {
    hostname: options.hostname,
    port: 443,
    path: options.path,
    method: 'GET',
    cert: fs.readFileSync(options.certFile),
    key: fs.readFileSync(options.keyFile),
    headers: {'AID': options.aftaleId
             },
    };

  opt.agent = new https.Agent(opt);

  try {
    const r = await httpsGet(opt, options.timeout);
    return (r.statusCode === options.statusCode && r.body.includes(options.string)) ? 1 : 0;
  } catch (error) {
    console.error(error);
  }
};

function httpsGet(opts, timeout) {
  return new Promise((resolve, reject) => {
    const req = https.get(opts, (res) => {
      let body = '';
      res.on('data', (data) => {
        body += data.toString();
      });

      res.on('end', () => {
        resolve({body, statusCode: res.statusCode});
      });
    });

    req.setTimeout(timeout, function() {
      req.destroy('error');
    });

    req.on('error', (e) => {
      console.error(e);
      reject(e);
    });
  });
};

推荐答案

在被声明为同一模块中使用的函数不能被伪造,除非该函数始终作为某些对象的方法使用,这既麻烦又不兼容ES模块:

A function that is used in the same module it was declared cannot be spied mocked, unless it's consistently as a method of some object, which is cumbersome and incompatible with ES modules:

module.exports.httpsGet = ...

...

module.exports.httpsGet(...);

否则,应将一个函数移至可以模拟的另一个模块,或者应按原样对其进行测试.在这种情况下,可以模拟基础API(https.get).

Otherwise a function should be moved to another module that can mocked, or should be tested as is. In this case underlying API (https.get) can be mocked instead.

这篇关于如何在Jest中模拟嵌套函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆