es6模块中其他函数使用的存根函数

时间:2016-09-07 11:18:46

标签: javascript testing ecmascript-6 sinon

我一直在考虑如何测试同一文件中其他函数使用的特定函数。

例如,假设我在一个文件中有两个函数:

// validators.js
export const required = ...;
export const containsUppercase = ...;
export const containsNumber = ...;

export const password = (val) => [required, containsUppercase, containsNumber].every(f => f(val));

很明显,密码验证器取决于requiredcontainsUppercasecontainsNumber函数。但是,如果我想把它们排除在外,那么我的测试实际上并不需要关心这些功能或它们如何验证。

这是一个简单而愚蠢的例子,但我遇到了更复杂情况的同样问题。

例如,如果我尝试用sinon执行此操作,我可能会尝试这样做:

import * as validators from './validators';

sinon.stub(validators, 'required').returns(false);
sinon.stub(validators, 'containsUppercase').returns(true);
sinon.stub(validators, 'containsNumber').returns(true);

// test
expect(validators.password('notImportant')).toBe(false);

我尝试过这样做,但我无法让它发挥作用。我发现如果我做了类似的事情,我可以让它工作,虽然我还没有测试过。

const required = ...;
const containsUppercase = ...;
const containsNumber = ...;

const password = (val) => [ex.required, ex.containsUppercase, ex.containsNumber].every(f => f(val));

export default ex = {
  required,
  containsUppercase,
  containsNumber,
  password,
}

这个解决方案也很难看,因为我现在不得不担心在正确的位置导出函数,并通过导出对象引用它。

有更清洁的方法吗?或者更确切地说,测试这些功能的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

第二个代码段中的模式是正确的。 adjustsFontSizeToFitWidth应该引用对象方法,以便在password范围之外模拟它们。

在JS中自然地实现这种行为的方法是使用validators.js

this

或者,使用普通(非箭头)功能:

export class Validators {
  required = (...) => { ... }
  ...
  password = (val) => [this.required, ...].every(...);
}

export default new Validators;

在第二种情况下,export default { required(...) { ... } ... password(val) { [this.required, ...].every(...); } } 等方法如果在required被调用时使用this,则应另外绑定。

答案 1 :(得分:1)

“但每次都要调用密码(requiredFn,uppercaseFn,numberFn,val)对我来说似乎不太有吸引力。”

您可以使用参数的默认值:

const defaultValidators = [required, containsUppercase, containsNumber];
const password = (value, validators = defaultValidators) => validators.every(f => f(value));

这允许您同时调用password('pass')password('pass', [v => false]),从而存根验证函数。