使用Sinon终止单个导出功能

时间:2019-06-14 09:20:08

标签: javascript testing sinon

我刚刚将lodash导入从func login(email: String , password: String){ let post_data = NSMutableDictionary() post_data.setValue(email, forKey: "username") post_data.setValue(password, forKey: "password") let urlLis = "https://yourbaseUrl/ios/v1/auth/login" let parameter = [ "email": email, "password": password ] Alamofire.request(urlLis, method: .post, parameters: parameter, encoding: URLEncoding.default, headers: nil) .validate(statusCode: 200..<300) .responseJSON { response in switch response.result { case .success(let data): print("isi: \(data)") self.navigationController?.pushViewController(vcbMasuk, animated: true) case .failure(let error): alert.addAction(UIAlertAction(title: "Close", style: .default, handler: { (_: UIAlertAction) in print("OK") })) self.present(alert, animated: true, completion: nil) print("need text") print("Request failed with error: \(error)") } } } 更改为import _ from 'lodash';
在我的测试中,我曾经有import debounce from 'lodash/debounce';,但是现在我对将其更改为什么感到困惑。显然sandbox.stub(_, 'debounce').returnsArg(0);不起作用。从模块仅导出单个功能时,不确定该怎么办。

2 个答案:

答案 0 :(得分:0)

此语法:

import something from 'myModule';

...是ES6语法,它将something绑定到default'的'myModule导出。

如果模块是ES6模块,则可以像下面这样对模块的default导出进行存根:

import * as myModule from 'myModule';
const sinon = require('sinon');

// ...

const stub = sinon.stub(myModule, 'default');

...但是这仅在'myModule'是ES6模块时有效。

在这种情况下,'lodash/debounce'不是ES6模块,它是预先编译的。最后一行是这样的:

module.exports = debounce;

...这表示模块导出去抖功能。

这意味着要存根'lodash/debounce',您必须模拟整个模块。

Sinon不提供模块级模拟,因此您需要使用类似proxyquire的东西:

const proxyquire = require('proxyquire');
const sinon = require('sinon');

const debounceStub = sinon.stub().returnsArg(0);
const code = proxyquire('[path to your code]', { 'lodash/debounce': debounceStub })

...或者如果您使用的是Jest,则可以使用类似jest.mock的内容:

jest.mock('lodash/debounce', () =>
  jest.fn((func, ms) => func)  // <= mock debounce to simply return the function
);

详细信息

仅在模块为ES6模块的情况下才暂停default模块导出的原因是因为编译期间发生了什么。

ES6语法被编译到ES6之前的JavaScript中。例如,Babel将其变为:

import something from 'myModule';

...变成这样:

var _myModule = _interopRequireDefault(require("myModule"));

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ?
    obj :  // <= return the result of require("myModule") if it is an ES6 module...
    { default: obj };  // <= otherwise set it to the default property of a wrapper object
}

...因此,如果'myModule'是ES6模块,它将直接返回...但是,如果不是,则互操作返回一个包装对象。

由于每个import获得一个不同的包装对象,因此更改其中一个的default属性不会影响其他任何对象的default属性。

答案 1 :(得分:0)

您可以使自己成为包装文件,最终将为您导出相同的lodash/debounce实例,但是这次您可以对它进行存根,例如:

myutils / lodash / debounce.js

import lodashDebounce from 'lodash/debounce';

const exports = {
    debounce: lodashDebounce,
};

export const debounce = () => exports.debounce();

export default exports;

现在,在您的实际代码中,debounce不是从原始位置而是从该包装文件中导入:

之前:

import debounce from 'lodash/debounce' // this is how we usually do

之后:

import { debounce } from 'myutils/lodash/debounce' // if we want to stub it


// all other code-lines remain the same
const method = () => {
    debounce(callback, 150));
    ...
}

现在执行 test.js 时:

import lodashWrapped from 'myutils/lodash/debounce';

sinon.stub(lodashWrapped , 'debounce').callsFake((callbackFn) => {
  // this is stubbed now
});

// go on, make your tests now