使用moment.js进行单元测试

时间:2016-12-14 13:53:36

标签: javascript unit-testing jasmine

我是编写单元测试的新手,需要一些帮助来测试函数的一部分。

我的功能看起来像这样......

getData() {
return this.parameters.map(p => {
        return {
            name: p.name,
            items: p.items.map(item => {

                const toTime = item.hasOwnProperty('end') ? moment.utc(item.end._d).unix() : null;
                const fromTime = item.hasOwnProperty('start') ? moment.utc(item.start._d).unix() : null;

                return {
                    id: item.id,
                    fromTime: fromTime,
                    toTime: toTime,
                };
            }),
        };
    });
}

到目前为止我的测试看起来像这样(茉莉花)

describe('getData()', function() {
it('should return json data', function() {
    $ctrl.parameters = [{
        name: 'test',
        items: [{
            id: 1,
            fromTime: null,
            toTime: null
        }, {
            id: 13,
            fromTime: null,
            toTime: null

        }]
    }];

    expect($ctrl.getData()).toEqual([{
        name: 'test',
        items: [{
            id: 1,
            fromTime: null,
            toTime: null
        }, {
            id: 13,
            fromTime: null,
            toTime: null
        }]
    }]);
});
});

这个测试正在工作/通过,但正如你所看到的,我没有测试使用Moment.js的三元if / else。基本上三元组的工作是检查项是否包含名为start / end的属性,如果包含,则将该值转换为epoch / unix时间戳并将其分配给toTime或{ {1}}。因此,如果项目具有名为end的属性,其值为fromTime,那么它将转换为'Sat Oct 31 2015 00:00:00 GMT+0000 (GMT)'并分配给'1446249600'

希望这能解释它!我不确定如何为它编写测试,并希望得到任何帮助/建议。

1 个答案:

答案 0 :(得分:6)

最简单的选择是手动为输入构建几个示例日期。例如:

$ctrl.parameters = [{
    name: 'test',
    items: [{
        id: 1,
        start: moment.utc('2017-01-01T01:00:00'),
        end: moment.utc('2017-01-01T06:00:00')
    }, {
        id: 13,
        start: moment.utc('2017-01-02T08:00:00'),
        end: null

    }]
}];

(请注意,在上面的示例中,我分别将fromTimetoTime更改为startend,因为这是getData所期望的输入。)

然后找出他们的unix时间戳。您可以在外部执行此部分 - 例如,我刚刚在moment.js网站上打开了浏览器开发人员工具(F12),在控制台中评估了以下语句,并获取了时间戳值:

moment.utc('2017-01-01T01:00:00').unix()
moment.utc('2017-01-01T06:00:00').unix()
moment.utc('2017-01-02T08:00:00').unix()

最后,回到单元测试中,只需验证时间戳是否符合预期值:

expect($ctrl.getData()).toEqual([{
  name: 'test',
  items: [{
    id: 1,
    fromTime: 1483232400,
    toTime: 1483250400
  }, {
    id: 13,
    fromTime: 1483344000,
    toTime: null
  }]
}]);

或者,如果您不想在单元测试中使用硬编码时间戳,则可以将每个示例日期存储在其自己的变量中(例如start1end1),然后进行比较,例如,start1.unix()

// Arrange
const start1 = moment.utc('2017-01-01T01:00:00');
const end1 = moment.utc('2017-01-01T06:00:00');
const start2 = moment.utc('2017-01-02T08:00:00');
$ctrl.parameters = [{
    name: 'test',
    items: [{
        id: 1,
        start: start1,
        end: end1
    }, {
        id: 13,
        start: start2,
        end: null

    }]
}];

// Act
const result = $ctrl.getData();

// Assert
expect(result).toEqual([{
  name: 'test',
  items: [{
    id: 1,
    fromTime: start1.unix(),
    toTime: end1.unix()
  }, {
    id: 13,
    fromTime: start2.unix(),
    toTime: null
  }]
}]);

这很好,因为单元测试是为了测试你的代码,而不是moment.js。这取决于你。

另请注意,我使用Arrange-Act-Assert模式来组织测试。再一次,取决于你,但是一旦你的单元测试开始变得复杂,那往往会让事情变得更容易理解。

无论哪种方式,您都需要在toTime方法中更改计算fromTimegetData的方式,因为如果您传入{{1},则所写的代码将无效} nullstart。特别是,如果您为end传入item.hasOwnProperty('start')值,null将返回true,但由于它会尝试评估start,因此会出错。 相反,我建议将这两行更改为以下内容:

item.start._d

我还建议不要使用moment对象的const toTime = item.end ? moment.utc(item.end._d).unix() : null; const fromTime = item.start ? moment.utc(item.start._d).unix() : null; 属性,因为那是一个内部(私有)变量。由于_dstart已经是时刻对象,因此您可以这样做:

end

此处提供了包含以上所有建议更改的完整jsbin示例:

https://jsbin.com/xuruwuzive/edit?js,output

请注意,必须进行一些调整,使其在AngularJS的上下文之外运行(使getData成为一个直接接受其参数的独立函数,而不是通过const toTime = item.end ? item.end.unix() : null; const fromTime = item.start ? item.start.unix() : null; )。