简体   繁体   English

如何使用Jasmine对带有回报的多个链接函数进行单元测试?

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

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)') TypeError:undefined不是构造函数(评估'allowedKeys.includes(key)')

I do not understand, how to fix that error? 我不明白,该如何解决该错误?

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. 对我来说,我认为我们不应该通过调用茉莉花模拟来接触Array, Object的原始功能。
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. 当然,有时我们必须模拟某些功能,例如当我们有http请求并且必须等待时,或者我们有其他地方的功能要使用并且想要模拟它们。
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. 但是在这种情况下,您的函数并不是真正expect to be called某个函数,它就足够了,并且不依赖任何其他函数。
So best we should only focus on the input and output values of function 所以最好只关注函数的输入和输出值

First of all, Object does not have a function filter and your jasmine.createSpyObj is literally useless. 首先, Object没有函数filter而您的jasmine.createSpyObj实际上是无用的。 As @Luan Phan says in his answer, we usually tend to test the input and output value for the function. 正如@Luan Phan在回答中所说,我们通常倾向于测试该函数的输入和输出值。 Javascript built-in functions do not need to be tested in our tests. Javascript内置函数无需在我们的测试中进行测试。

But, if you would like to know, for example, if Object.keys was called inside your function, here is an example 但是,例如,如果您想知道是否在函数内部调用了Object.keys ,则可以举一个例子

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 对于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. 同样,Javascript的内置函数已经在其他地方编写了测试,我们不需要在测试中对其进行测试,我们的重点应该放在编写的函数上。

Hope it helps 希望能帮助到你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM