How to unit test with Jasmine on multiple chained functions with returns?

谁说胖子不能爱 提交于 2019-12-24 17:08:34

问题


I have the following function:

/**
* filters array down to the given allowed keys
* @param {Object} data
* @param {String[]} allowedKeys
*/
$scope.filterData = function(data, allowedKeys) {
    return Object.keys(data)
        .filter(function(key) {
            return allowedKeys.includes(key);
        })
        .reduce(function(obj, key) {
            obj[key] = data[key];
            return obj;
        }, {});
};

that I want to create a unit test for and so far I have the following:

describe('$scope.filterData', function() { 
        //params
        var data = {
            key1: "value1",
            key2: "value2",
            key3: "value3"
        }
        var allowedKeys = ["key1", "key2"];
        //mockobject
        var $Object = jasmine.createSpyObj('Object', ['keys', 'filter', 'reduce']);

        it('should func', function() {

            $Object.keys.and.returnValue($Object);
            $Object.filter.and.returnValue($Object);
            $Object.reduce.and.returnValue($Object);

            $scope.filterData(data, allowedKeys);
            expect(Object.filter).toHaveBeenCalled();
        });
    });

The issue that I am having, is that I am getting the following error:

TypeError: undefined is not a constructor (evaluating 'allowedKeys.includes(key)')

I do not understand, how to fix that error?


回答1:


I don't if this solution could help you or not
When we write test case, especially test for functions, we tend to test the input and output value for the function.
And for me, I think we shouldn't touch the primitive function of Array, Object by calling jasmine mock.
If you want to know if your function is working properly in this case.

For example:

describe('$scope.filterData', function() { 
    //params
    var data = {
        key1: "value1",
        key2: "value2",
        key3: "value3"
    }
    var allowedKeys = ["key1", "key2"];

    it('should return 2 key', function() {            
        var expected = {
          key1: "value1",
          key2: "value2",
        }

        var value = $scope.filterData(data, allowedKeys);
        expect(JSON.stringify(value)).toEqual(JSON.stringify());
    });
});

Of course we have to mock some functions sometimes, like when we have the http request and have to wait, or we have function from other places to use and want to mock them.
But in this case, your function is not really necessary for expect some function to be called, it's simply enough and don't depend on anything else.
So best we should only focus on the input and output values of function




回答2:


First of all, Object does not have a function filterand your jasmine.createSpyObj is literally useless. As @Luan Phan says in his answer, we usually tend to test the input and output value for the function. Javascript built-in functions do not need to be tested in our tests.

But, if you would like to know, for example, if Object.keys was called inside your function, here is an example

it('should func', function () {                        
    spyOn(Object, 'keys').and.callThrough();

    $scope.filterData(data, allowedKeys);                     

    expect(Object.keys).toHaveBeenCalled();
});

The same can be done for the rest of the built-in functions used in filterData

it('should func', function () {
    spyOn(Object, 'keys').and.callThrough();
    spyOn(Array.prototype, 'filter').and.callThrough();
    spyOn(Array.prototype, 'reduce').and.callThrough();

    $scope.filterData(data, allowedKeys);

    expect(Object.keys).toHaveBeenCalled();
    expect(Array.prototype.filter).toHaveBeenCalled();
    expect(Array.prototype.reduce).toHaveBeenCalled();
});

If you really need to mock what one of the built-in functions returns, here is an example

it('should func', function () {
    const mockResult = {};

    spyOn(Array.prototype, 'reduce').and.returnValue(mockResult);

    const result = filterData(data, allowedKeys);

    expect(result).toBe(mockResult);
});

Again, Javascript's built-in functions already have tests written in some other place, we don't need to test it in our test, our focus should be on the functions we write.

Hope it helps



来源:https://stackoverflow.com/questions/51331618/how-to-unit-test-with-jasmine-on-multiple-chained-functions-with-returns

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