sinos stub与es6承诺的对象 [英] sinon stub with es6-promisified object

查看:166
本文介绍了sinos stub与es6承诺的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

确定我的设置如下:
使用节点6.2,es6-promisify,sinon,sinon-as-promised和babel来支持es6导入/导出。

Ok my setup is as follows: Using node 6.2, es6-promisify, sinon, sinon-as-promised, and babel to transpile support for es6 import/export.

我的测试代码看起来像这样:

My code under test looks something like this:

const client = restify.createJsonClient({
    url: 'http://www.example.com'
});
export let get = promisify(client.get, {thisArg: client, multiArgs: true});

export default function* () {
    yield get('/some/path');
}

然后在我的测试文件中,我有这样的东西:

And then in my test file I have something like this:

import * as m from mymodule;
it('should fail', function(done) {
    let stub = sinon.stub(m, 'get').rejects('i failed');
    client.get('/endpoint/that/leads/to/mymodule/call', function(err, req, res, data) {
        stub.called.should.be.eql(true); // assertion fails!!
        done();
    }
});

ve也尝试存储原来的client.get调用,这也不行。我唯一需要工作的是每一次通话,并且原始的client.get,这似乎很跛脚。例如:

I've also tried stubbing the original client.get call, and that doesn't work either. The only thing I've gotten to work is promisifying on the fly with each call, and stubbing the original client.get, which seems pretty lame. E.g.:

export const client = restify.createJsonClient({
    url: 'http://www.example.com'
});
function get() {
    return promisify(client.get, {thisArg: client, multiArgs: true});
}

export default function* () {
    yield get('/some/path');
}

和测试代码这样做:

import {module_client} from mymodule;
it('should fail', function(done) {
    let stub = sinon.stub(module_client, 'get').yields('i failed');
    client.get('/endpoint/that/leads/to/mymodule/call', function(err, req, res, data) {
        stub.called.should.be.eql(true); // assertion succeeds
        done();
    }
});

所以问题如果不是很明显,为什么我的原始代码不能正常工作?有没有办法使存根工作,而不会让每次原始的重新定义(例如,其他人如何获得这种工作)?

And so the question, if it's not completely obvious, is why does my original code not work? And is there a way to make the stub work without promisifying the original restify each time (e.g. how do other people get this sort of thing working)?

编辑:

当前代码如下:

const client = restify.createJsonClient({
    url: 'http://www.example.com'
});

export let get = promisify(client.get, {thisArg: client, multiArgs: true});

export default function*() {
    try {
        console.log(exports.get); // <= a large sinon stub object, I'll post that below
        yield exports.get(); // <= throws here, "exports.get is not a function"
    }
    catch(ex) {
        log.error('got an error', ex);
        throw ex;
    }
}

console.log打印如下内容:

The console.log prints the following:

{ [Function: proxy]
  isSinonProxy: true,
  reset: [Function],
  invoke: [Function: invoke],
  named: [Function: named],
  getCall: [Function: getCall],
  getCalls: [Function],
  calledBefore: [Function: calledBefore],
  calledAfter: [Function: calledAfter],
  withArgs: [Function],
  matches: [Function],
  printf: [Function],
  calledOn: [Function],
  alwaysCalledOn: [Function],
  calledWith: [Function],
  calledWithMatch: [Function],
  alwaysCalledWith: [Function],
  ....

EDIT2:

FWIW,生成的代码是这样的:

And FWIW, the babel generated code is producing this:

let get = exports.get = (0, _es6Promisify2.default)(client.get, { thisArg: client, multiArgs: true });

EDIT3:

Ok超级奇怪。我更改了我的源代码:

Ok super weird. I changed my source to do this instead:

const client = restify.createJsonClient({
    url: 'http://www.example.com'
});

export let get = promisify(client.get, {thisArg: client, multiArgs: true});

export default function*() {
    try {
        let thePromise = exports.get(); // e.g. call exports.get on separate line from the yield
        yield thePromise; // and the throw now says 'undefined is not a function'. I should note that in both cases, the stack trace shows the error on node_modules/co/index.js at line 65.
    }
    catch(ex) {
        log.error('got an error', ex);
        throw ex;
    }
}


推荐答案

问题最终与ES6导入/导出工作的方式有关,具体来说,它们如何使您的代码看起来更好,但是可以避免轻易的间谍/ stubbing。

The problem ultimately has to do with how ES6 import/exports work, and specifically, how they make your code look better but prevent easy spying/stubbing.

以此示例模块:

// my-module.js
function someFunction() {
  console.log('original');
};

export let get = someFunction;

export default function() {
  get();
};

该代码的测试用例可能如下所示:

A test case for that code could look like this:

import * as sinon from 'sinon';
import * as should from 'should';
import setup, * as myModule from './my-module';

it('should call get()', () => {
  let stub = sinon.stub(myModule, 'get');
  setup();
  stub.called.should.eql(true);
});

你会看到原来的 get()被调用,而不是存根。这是因为在模块中, get 是本地(对模块)的引用。在导出的对象中,Sinon将另一个引用到同一个函数。

You'll see that the original get() gets called, and not the stub. This is because in the module, get is a local (to the module) reference. Sinon is stubbing another reference to the same function, in the exported object.

为了使这个工作,而不是在模块,您需要使用导出对象中的一个:

To make this work, instead of using a local reference in the module, you need to use the one in the exported object:

export default function() {
  exports.get();
};

其中,唉,使得更糟糕的代码。

Which, alas, makes for uglier code.

这篇关于sinos stub与es6承诺的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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