Sinon可以更轻松地对ES6构造函数进行打桩吗? [英] Can ES6 constructors be stubbed more easily with Sinon?

查看:75
本文介绍了Sinon可以更轻松地对ES6构造函数进行打桩吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出(过于简化的)代码段:

Given the (overly simplified) snippet:

import Validator from 'validator';

export default function isValid(arg) {
  // Validator#isValid is an ES6 getter
  return new Validator(arg).isValid;
}   

我如何测试 Validator 是用给定的参数实例化的吗?和存根 isValid

How can I test that a Validator was instantiated with the given parameter? And stub isValid?

我知道我可以重组代码为了避免该问题,我并没有找到解决方法,因为我发现了很多方法(依赖注入,未使用ES6糖等)。

I know I can restructure my code to avoid the issue, I am not looking for a workaround as I found plenty (dependency injection, not using ES6 sugar, etc.).

我找到了一种方法,但是这真是丑陋。在测试文件中:

I found a way, but it is terribly ugly. In test file:

import ValidatorNamespace from 'validator';

const Validator = ValidatorNamespace.default;
let validatorInstance;
let validatorConstructor;

const subject = arg => isValid(arg);
const validityStatus = true;

describe('isValid helper', () => {
  beforeEach(() => {
    validatorInstance = sinon.createStubInstance(Validator);

    // Yay! This is how I managed to spy on the constructor!.. :(
    validatorConstructor = sandbox.stub(ValidatorNamespace, 'default').
      returns(validatorInstance);

    sandbox.stub(validatorInstance, 'isValid').value(validityStatus);
  });

  it('instantiates the validator properly', ()=> {
    subject('arg');
    expect(validatorConstructor).to.have.been.calledWith('arg')
  });

  it('returns the value returned by the validator', ()=> {
    expect(subject('arg')).to.eq(validityStatus);
  });
});

验证者代码:

export default class Validator {
  constructor(arg) {
    this.innerValue = arg;
  }

  get isValid() {
    return aFunctionOf(this.innerValue);
  }
}


推荐答案

真的不可能。存根需要某种接缝,通过它可以将存根放置到位。直接在生产代码中导入函数(构造函数或其他构造函数)时,剩下的唯一缝就是导入过程本身。

What you want isn't really possible. Stubbing requires some kind of "seam" through which to put the stubs in place. When you import functions (constructors or otherwise) directly in your production code, the only seam you're leaving is the import process itself.

proxyquire ,它将覆盖节点中的 require 调用。我不知道您使用的环境是什么,我真的不知道ES6模块在此环境下的表现如何。不过,如果您使用babel转换到ES6,它应该可以工作。

There is proxyquire, which overrides require calls in node. I don't know what environment you're using, and I don't really know how well this plays with ES6 modules. If you're transpiling to ES6 using babel, though, it should work.

根据我的经验,这种东西不值得额外的复杂性。我通常的解决方法是仅使一个静态工厂函数并存根/使用它,而不是直接使用构造函数:

In my experience this kind of stuff is not worth the additional complexity. My usual workaround is to just make a static factory function and stub/use that instead of using the constructor directly:

export default class Validator {
  constructor(arg) {
    this.innerValue = arg;
  }

  static create(arg) {
    return new Validator(arg);
  }

  get isValid() {
    return aFunctionOf(this.innerValue);
  }
}

如果要对工厂进行单元测试,则可以可以简单地检查返回的实例,而不用存根构造函数:

If you want a unit test for the factory, you can simply check the returned instance instead of stubbing the constructor:

it('create should return an instance', function() {
  let arg = { foo: 'bar' };

  let result = Validator.create(arg);

  expect(result).to.be.an.instanceof(Validator);
  expect(result.innerValue).to.equal(arg);
});

这篇关于Sinon可以更轻松地对ES6构造函数进行打桩吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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