How to test two returned functions with different argument value in javascript?

亡梦爱人 提交于 2020-01-16 18:00:33

问题


I have a function that returns comparisonFunction

  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;
  }

This method will be used inside javascript "sort" method. for example:

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

This method will sort "arrayOfObjects" by "name" property. Method works fine, question is: how i can compare function call with different arguments

  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());
  });

This is what i have now, but it doesn't works. The error i am receiving after running the code is:

 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;
            }'.

回答1:


Checking the code of the function as a test very brittle and can break easily giving you a false negative:

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
}

Just making non-functional changes to the code breaks the test.

Worse yet, if there are functional changes to the code, the test cannot guarantee that the new implementation behaves like the old one, since it only looks at the structure of the code:

//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
};

Instead, what you want to do it test the behaviour of the code and set your expectations there. That way, if the implementation changes, you can make sure that the implementation still conforms to the same set of expectations.

In this case, you need to create a sample input that is initially unordered, try to order it and then expect that the order worked as you expected. In pseudo-code that would look a bit like this:

//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);

You can also add more tests at a more granular level to bind the expectations even more, if you want. For example, if you want to ensure that the comparison is case-sensitive

//arrange
a = { testProperty: "a" };
b = { testProperty: "B" };

//act
result = component.getComparisonFunction('testProperty')(a, b)

//assert
expect(result).toBeGreaterThanOrEqual(1)

Or case-insensitive:

//arrange
a = { testProperty: "a" };
b = { testProperty: "B" };

//act
result = component.getComparisonFunction('testProperty')(a, b)

//assert
expect(result).toBeLessThanOrEqual(-1)

This defines your expectations much more clearly and makes sure that future changes will cover exactly what you need.




回答2:


If you want to achieve sort via any param provided, you can try following :

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);

Moreover, to test it simply have test cases like above and check if its sorting as per your implementation.



来源:https://stackoverflow.com/questions/56805478/how-to-test-two-returned-functions-with-different-argument-value-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!