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

时间:2018-07-13 19:23:02

标签: javascript angularjs unit-testing jasmine

我具有以下功能:

/**
* 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;
        }, {});
};
我要为其创建单元测试的

到目前为止,我具有以下内容:

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

我遇到的问题是出现以下错误:

  

TypeError:未定义不是构造函数(正在评估'allowedKeys.includes(key)')

我不明白,如何解决该错误?

2 个答案:

答案 0 :(得分:0)

我不知道这种解决方案是否可以帮助您
在编写测试用例时,尤其是对功能进行测试时,我们倾向于测试功能的输入和输出值。
对我来说,我认为我们不应该通过调用茉莉花模拟来触及Array, Object的原始功能。
如果您想知道函数在这种情况下是否正常运行。

例如:

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

当然,有时我们必须模拟一些函数,例如当我们有http请求并且必须等待时,或者我们有其他地方的函数要使用并且想要模拟它们。
但是在这种情况下,您的功能对于expect某些功能to be called并不是真正必需的,它足够简单,并且不依赖任何其他内容。
因此,最好只关注输入内容和功能的输出值

答案 1 :(得分:0)

首先,Object没有函数filter,而您的jasmine.createSpyObj实际上是无用的。正如@Luan Phan在回答中所说,我们通常倾向于测试该函数的输入和输出值。无需在我们的测试中对Javascript内置函数进行测试。

但是,例如,如果您想知道是否在函数内部调用了Object.keys,则为示例

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

    $scope.filterData(data, allowedKeys);                     

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

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

如果您真的需要 mock 内置函数之一返回的内容,请参考以下示例

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

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

    const result = filterData(data, allowedKeys);

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

同样,Javascript的内置函数已经在其他地方编写了测试,我们不需要在测试中对其进行测试,我们的重点应该放在编写的函数上。

>

希望有帮助