admin管理员组

文章数量:1310415

I'm new to writing unit tests.

My function looks like this:

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

and so far my Jasmine test looks like this:

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

This test is working/passing, but as you can see I am not testing the ternary if/else that uses Moment.js. Basically what the ternary does is check if items contains a property called start / end and if it does, convert that value to a epoch/Unix timestamp and assign it to either toTime or fromTime.

So if items had a property called end with a value of 'Sat Oct 31 2015 00:00:00 GMT+0000 (GMT)', then it would be converted to '1446249600' and assigned to toTime.

How can I write a test for it?

I'm new to writing unit tests.

My function looks like this:

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

and so far my Jasmine test looks like this:

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

This test is working/passing, but as you can see I am not testing the ternary if/else that uses Moment.js. Basically what the ternary does is check if items contains a property called start / end and if it does, convert that value to a epoch/Unix timestamp and assign it to either toTime or fromTime.

So if items had a property called end with a value of 'Sat Oct 31 2015 00:00:00 GMT+0000 (GMT)', then it would be converted to '1446249600' and assigned to toTime.

How can I write a test for it?

Share Improve this question edited May 31, 2022 at 21:41 halfer 20.3k19 gold badges109 silver badges202 bronze badges asked Dec 14, 2016 at 13:53 Jose the hoseJose the hose 1,89510 gold badges33 silver badges58 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 7 +50

The simplest option is to just construct a couple example dates manually for the input. For example:

$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

    }]
}];

(Note in the above example, I changed fromTime and toTime to start and end, respectively, since that is what getData is expecting for the input.)

Then figure out their unix timestamps. You can do this part externally - for example, I just opened up the browser developer tools (F12) on the moment.js website, evaluated the following statements in the console, and grabbed the timestamp values:

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

Finally, back in the unit test, just verify that the timestamps match the expected values:

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

Alternatively, if you would rather not have hardcoded timestamps in your unit tests, you can instead store each example date in its own variable (e.g., start1, end1), and then pare to, e.g., 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
  }]
}]);

That's perfectly fine, since the unit test is meant to test your code, not moment.js. It's up to you.

Note also that I am using the Arrange-Act-Assert pattern for organizing the test. Again, up to you, but once your unit tests start to get plicated, that tends to keep things easier to follow.

Either way, you will need to change how you pute toTime and fromTime in your getData method, since the code as written will not work if you pass in null for either start or end. In particular, item.hasOwnProperty('start') will return true if you pass in a null value for start, but it will error out because it tries to evaluate item.start._d. Instead, I remend changing those 2 lines to the following:

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

I would also advise against using the _d property of the moment object, since that is an internal (private) variable. Since start and end are already moment objects, you may instead be able to just do this:

const toTime = item.end ? item.end.unix() : null;
const fromTime = item.start ? item.start.unix() : null;

A plete jsbin example containing all of the above remended changes is available here:

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

Note that some tweaks had to be made so it runs outside the context of AngularJS (make getData a standalone function that accepts its parameters directly, rather than via $ctrl).

本文标签: javascriptUnit test with momentjsStack Overflow