【问题标题】:How to test two returned functions with different argument value in javascript?如何在javascript中测试两个具有不同参数值的返回函数?
【发布时间】:2019-11-10 07:52:26
【问题描述】:

我有一个返回比较函数的函数

  getComparisonFunction(propertyOfComparison) {
    const func = function(a, b){
      if ( a[propertyOfComparison] < b[propertyOfComparison] ) {
        return -1;
      }
      if ( a[propertyOfComparison] > b[propertyOfComparison] ) {
        return 1;
      }
      return 0;
    };

    return func;
  }

此方法将在javascript“排序”方法中使用。 例如:

arrayOfObjects.sort(getComparisonFunction('name'));

此方法将按“名称”属性对“arrayOfObjects”进行排序。 方法工作正常,问题是: 我如何将函数调用与不同的参数进行比较

  it('should get correct comparison function', function () {
    const func = component.getComparisonFunction('testProperty');

    const expectedFunc = function(a, b){
      if ( a['testProperty'] < b['testProperty'] ) {
        return -1;
      }
      if ( a['testProperty'] > b['testProperty'] ) {
        return 1;
      }
      return 0;
    };

    expect(func.toString()).toEqual(expectedFunc.toString());
  });

这是我现在拥有的,但它不起作用。运行代码后我收到的错误是:

 Expected 'function (a, b) {
                if (a[propertyOfComparison] < b[propertyOfComparison]) {
                    return -1;
                }
                if (a[propertyOfComparison] > b[propertyOfComparison]) {
                    return 1;
                }
                return 0;
            }' to equal 'function (a, b) {
                if (a['testProperty'] < b['testProperty']) {
                    return -1;
                }
                if (a['testProperty'] > b['testProperty']) {
                    return 1;
                }
                return 0;
            }'.

【问题讨论】:

  • 检查字符串化函数是非常脆弱的,正如您刚刚经历的那样。通常,您测试行为,并且不要期望额外的换行符或分号或任何无关紧要的东西破坏您的测试。因此,制作一个您知道要如何排序的列表,对其进行排序,然后检查排序顺序是否与您期望的相同。
  • 事情是我不想测试比较功能,它工作正常。我现在正在测试“getComparisonFunction()”是否返回我期望的值。
  • 我说这是错误的方法。你几乎不想在你尝试的细节级别上测试确切的实现。您测试行为,以便能够更改实现。如果您现在更改实现,您的测试将立即变得毫无价值 - 您可以更改测试,但您不能确定新返回的函数与旧函数的行为方式相同。
  • 我明白了,谢谢@VLAZ!您可以发表您的评论作为答案吗?
  • 这是打字稿和严格打字可以使这更容易的地方

标签: javascript angular jasmine karma-webpack


【解决方案1】:

如果您想通过提供的任何参数实现排序,您可以尝试以下操作:

const array=[
  {name:'C',Key:'14',val:3},
  {name:'B',Key:'12',val:2},
  {name:'A',Key:'11',val:1},
  {name:'D',Key:'16',val:4},
  {name:'E',Key:'18',val:5}
];

console.log(array);

function comparer(prop){
  return function(a,b){
    return a[prop]-b[prop];
  }
};
array.sort(comparer('Key'));
console.log(array);
array.sort(comparer('val'));
console.log(array);

此外,要对其进行测试,只需使用上述测试用例并检查其是否按照您的实现进行排序。

【讨论】:

    【解决方案2】:

    检查函数的代码作为测试非常很脆弱,很容易破坏给你一个假阴性:

    let someFn = function(a, b) {
      return a + b;
    }
    
    let expected = `function(a, b) {
      return a + b;
    }`
    
    console.log("Test original implementation:", test(someFn.toString(), expected));
    
    //later the code style is changed to remove extra whitespace and make it one line
    someFn = function(a, b) { return a+b; }
    
    console.log("Test updated implementation:", test(someFn.toString(), expected));
    
    //simple testing
    function test(expected, actual) {
      return expected == actual
    }

    只是对代码进行非功能性更改会破坏测试。

    更糟糕的是,如果对代码进行 功能更改,则测试无法保证新实现的行为与旧实现一样,因为它只查看代码的结构:

    //simplified case of what the actual code could be doing
    function someCodeBaseFunction() {
      let someInput = [8, 12, 42];
      return someFn(...someInput)
    }
    
    let someFn = function(a, b) { return a+b; }
    
    let expected = `function(a, b) { return a+b; }`
    
    console.log("Test original implementation:", test(someFn.toString(), expected));
    
    console.log("Codebase usage:", someCodeBaseFunction()); //20, as the third number is ignored
    
    //new implementation
    someFn = function(...args) { 
      return args.reduce((a, b) => a + b); 
    }
    
    //update the test, so it passes
    expected = `function(...args) { 
      return args.reduce((a, b) => a + b); 
    }`
    
    console.log("Test updated implementation:", test(someFn.toString(), expected));
    
    //some existing line of code
    console.log("Codebase usage:", someCodeBaseFunction()); //62, as the third number is now used
    
    //simple testing
    function test(expected, actual) {
      return expected == actual
    };

    相反,您要测试代码的行为,并在那里设定您的期望。这样,如果实施发生变化,您可以确保实施仍然符合相同的预期。

    在这种情况下,您需要创建一个最初无序的示例输入,尝试对其进行排序,然后期望该顺序按您的预期工作。在看起来有点像这样的伪代码中:

    //arrange
    input = [
     {testProperty: "c", id: 1},
     {testProperty: "a", id: 2},
     {testProperty: "d", id: 3},
     {testProperty: "b", id: 4}
    ];
    
    expected = [
     {testProperty: "a", id: 2},
     {testProperty: "b", id: 4},
     {testProperty: "c", id: 1},
     {testProperty: "d", id: 3}
    ];
    
    //act
    input.sort(component.getComparisonFunction('testProperty'))
    
    //assert
    expect(input).toEqual(expected);
    

    如果需要,您还可以添加更多更细粒度的测试,以进一步绑定期望。例如,如果您想确保比较区分大小写

    //arrange
    a = { testProperty: "a" };
    b = { testProperty: "B" };
    
    //act
    result = component.getComparisonFunction('testProperty')(a, b)
    
    //assert
    expect(result).toBeGreaterThanOrEqual(1)
    

    或不区分大小写:

    //arrange
    a = { testProperty: "a" };
    b = { testProperty: "B" };
    
    //act
    result = component.getComparisonFunction('testProperty')(a, b)
    
    //assert
    expect(result).toBeLessThanOrEqual(-1)
    

    这更清楚地定义了您的期望,并确保未来的更改将完全满足您的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-15
      • 1970-01-01
      • 2013-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-02
      • 1970-01-01
      相关资源
      最近更新 更多