I'm new to mocha, and I wanted to try using a for loop to create test cases. I want to test a function that I've made that takes an input of standard 12 hour time, and outputs it into 24 hour military time. This is what it looks like.
exports.main = function(time) {
var hr = parseInt(time.substr(0,2));
var period = time.substr(8,10);
if (period == 'AM' && hr == 12) {
hr = '0';
}
if (period == 'PM' && hr < 12) {
hr += 12;
}
hr.toString();
if (hr < 10) {
hr = '0' + hr;
}
return time = time.replace(/^\d{2}/g, hr).substr(0,8);
}
To test my function in mocha, I have two arrays, one array holds the standard times and the other holds the corresponding expected output. I want to iterate through them and produce a test case for each iteration and test my function.
test_array = ["12:00:00AM", "01:00:00AM", "02:00:00AM", "03:00:00AM", "04:00:00AM",
"05:00:00AM", "06:00:00AM", "07:00:00AM", "08:00:00AM", "09:00:00AM",
"10:00:00AM", "11:00:00AM", "12:00:00PM", "01:00:00PM", "02:00:00PM",
"03:00:00PM", "04:00:00PM", "05:00:00PM", "06:00:00PM", "07:00:00PM",
"08:00:00PM", "09:00:00PM", "10:00:00PM", "11:00:00PM"];
against = ["00:00:00", "01:00:00", "02:00:00", "03:00:00", "04:00:00",
"05:00:00", "06:00:00", "07:00:00", "08:00:00", "09:00:00", "10:00:00",
"11:00:00", "12:00:00", "13:00:00", "14:00:00", "15:00:00", "16:00:00",
"17:00:00", "18:00:00", "19:00:00", "20:00:00", "21:00:00", "22:00:00",
"23:00:00"]
This is what my test script looks like:
var converter = require('../modules/time.js');
describe('Time Converter', function() {
describe('main()', function() {
for(i = 0; i < 24; i++) {
it(test_array[i] + ' should convert to ' + against[i], function() {
var test = converter.main(test_array[i]);
assert.equal(test, against[i]);
});
}
});
});
The following is the results of the tests:
0 passing (23ms)
24 failing
1) Time Converter main() 12:00:00AM should convert to 00:00:00:
TypeError: Cannot read property 'substr' of undefined
at Object.exports.main (app/modules/time.js:43:27)
at Context.<anonymous> (app/test/test.js:35:26)
2) - 24) has the same result:
24) Time Converter main() 11:00:00PM should convert to 23:00:00:
TypeError: Cannot read property 'substr' of undefined
at Object.exports.main (app/modules/time.js:43:27)
at Context.<anonymous> (app/test/test.js:35:26)
However when I change the for loop to
for(i = 0; i < 23; i++)
All the tests pass except, naturally it doesn't test the last test case.
Time Converter
main()
✓ 12:00:00AM should convert to 00:00:00
✓ 01:00:00AM should convert to 01:00:00
✓ 02:00:00AM should convert to 02:00:00
✓ 03:00:00AM should convert to 03:00:00
✓ 04:00:00AM should convert to 04:00:00
✓ 05:00:00AM should convert to 05:00:00
✓ 06:00:00AM should convert to 06:00:00
✓ 07:00:00AM should convert to 07:00:00
✓ 08:00:00AM should convert to 08:00:00
✓ 09:00:00AM should convert to 09:00:00
✓ 10:00:00AM should convert to 10:00:00
✓ 11:00:00AM should convert to 11:00:00
✓ 12:00:00PM should convert to 12:00:00
✓ 01:00:00PM should convert to 13:00:00
✓ 02:00:00PM should convert to 14:00:00
✓ 03:00:00PM should convert to 15:00:00
✓ 04:00:00PM should convert to 16:00:00
✓ 05:00:00PM should convert to 17:00:00
✓ 06:00:00PM should convert to 18:00:00
✓ 07:00:00PM should convert to 19:00:00
✓ 08:00:00PM should convert to 20:00:00
✓ 09:00:00PM should convert to 21:00:00
✓ 10:00:00PM should convert to 22:00:00
23 passing (14ms)
However when I test the last test case by itself, it passes.
✓ 11:00:00PMshould convert to 23:00:00
So, I'm confused as to why all the tests don't work if the for loop iterates through the whole array, but works if I iterate up until the last index. Can someone clear this up for me?
I'm new to mocha, and I wanted to try using a for loop to create test cases. I want to test a function that I've made that takes an input of standard 12 hour time, and outputs it into 24 hour military time. This is what it looks like.
exports.main = function(time) {
var hr = parseInt(time.substr(0,2));
var period = time.substr(8,10);
if (period == 'AM' && hr == 12) {
hr = '0';
}
if (period == 'PM' && hr < 12) {
hr += 12;
}
hr.toString();
if (hr < 10) {
hr = '0' + hr;
}
return time = time.replace(/^\d{2}/g, hr).substr(0,8);
}
To test my function in mocha, I have two arrays, one array holds the standard times and the other holds the corresponding expected output. I want to iterate through them and produce a test case for each iteration and test my function.
test_array = ["12:00:00AM", "01:00:00AM", "02:00:00AM", "03:00:00AM", "04:00:00AM",
"05:00:00AM", "06:00:00AM", "07:00:00AM", "08:00:00AM", "09:00:00AM",
"10:00:00AM", "11:00:00AM", "12:00:00PM", "01:00:00PM", "02:00:00PM",
"03:00:00PM", "04:00:00PM", "05:00:00PM", "06:00:00PM", "07:00:00PM",
"08:00:00PM", "09:00:00PM", "10:00:00PM", "11:00:00PM"];
against = ["00:00:00", "01:00:00", "02:00:00", "03:00:00", "04:00:00",
"05:00:00", "06:00:00", "07:00:00", "08:00:00", "09:00:00", "10:00:00",
"11:00:00", "12:00:00", "13:00:00", "14:00:00", "15:00:00", "16:00:00",
"17:00:00", "18:00:00", "19:00:00", "20:00:00", "21:00:00", "22:00:00",
"23:00:00"]
This is what my test script looks like:
var converter = require('../modules/time.js');
describe('Time Converter', function() {
describe('main()', function() {
for(i = 0; i < 24; i++) {
it(test_array[i] + ' should convert to ' + against[i], function() {
var test = converter.main(test_array[i]);
assert.equal(test, against[i]);
});
}
});
});
The following is the results of the tests:
0 passing (23ms)
24 failing
1) Time Converter main() 12:00:00AM should convert to 00:00:00:
TypeError: Cannot read property 'substr' of undefined
at Object.exports.main (app/modules/time.js:43:27)
at Context.<anonymous> (app/test/test.js:35:26)
2) - 24) has the same result:
24) Time Converter main() 11:00:00PM should convert to 23:00:00:
TypeError: Cannot read property 'substr' of undefined
at Object.exports.main (app/modules/time.js:43:27)
at Context.<anonymous> (app/test/test.js:35:26)
However when I change the for loop to
for(i = 0; i < 23; i++)
All the tests pass except, naturally it doesn't test the last test case.
Time Converter
main()
✓ 12:00:00AM should convert to 00:00:00
✓ 01:00:00AM should convert to 01:00:00
✓ 02:00:00AM should convert to 02:00:00
✓ 03:00:00AM should convert to 03:00:00
✓ 04:00:00AM should convert to 04:00:00
✓ 05:00:00AM should convert to 05:00:00
✓ 06:00:00AM should convert to 06:00:00
✓ 07:00:00AM should convert to 07:00:00
✓ 08:00:00AM should convert to 08:00:00
✓ 09:00:00AM should convert to 09:00:00
✓ 10:00:00AM should convert to 10:00:00
✓ 11:00:00AM should convert to 11:00:00
✓ 12:00:00PM should convert to 12:00:00
✓ 01:00:00PM should convert to 13:00:00
✓ 02:00:00PM should convert to 14:00:00
✓ 03:00:00PM should convert to 15:00:00
✓ 04:00:00PM should convert to 16:00:00
✓ 05:00:00PM should convert to 17:00:00
✓ 06:00:00PM should convert to 18:00:00
✓ 07:00:00PM should convert to 19:00:00
✓ 08:00:00PM should convert to 20:00:00
✓ 09:00:00PM should convert to 21:00:00
✓ 10:00:00PM should convert to 22:00:00
23 passing (14ms)
However when I test the last test case by itself, it passes.
✓ 11:00:00PMshould convert to 23:00:00
So, I'm confused as to why all the tests don't work if the for loop iterates through the whole array, but works if I iterate up until the last index. Can someone clear this up for me?
Share Improve this question edited Oct 18, 2016 at 7:17 B. Kwok asked Oct 18, 2016 at 7:11 B. KwokB. Kwok 9032 gold badges9 silver badges13 bronze badges4 Answers
Reset to default 11Your code may be sync, but mocha calls it it async. Means: your it descriptions are parsed sync, mocha stores this information and runs every test in it's own context. This is async. To make this work, you have to create a closure with a function:
var converter = require('../modules/time.js');
// outside the loop:
function itShouldTestArray(i) {
// i is now within the function scope and won't change anymore
it(test_array[i] + ' should convert to ' + against[i], function() {
var test = converter.main(test_array[i]);
assert.equal(test, against[i]);
}
describe('Time Converter', function() {
describe('main()', function() {
for(i = 0; i < 24; i++) {
itShouldTestArray(i);
});
}
});
});
So, I'm confused as to why all the tests don't work if the for loop iterates through the whole array, but works if I iterate up until the last index. Can someone clear this up for me?
This is probably a very-hard-to-debug-problem caused by the asynchronous testing conducted by Mocha. It seems like that changing i
from 23 to 24 somehow results in your arrays being deleted before the tests are conducted, confer the error message:
TypeError: Cannot read property 'substr' of undefined
You can avoid this deletion of the arrays before testing time by assigning their values inside a closure:
var converter = require('../modules/time.js');
describe('Time Converter', function() {
describe('main()', function() {
test_array = // insert array inside closure;
against = //insert array inside closure;
callback = function () {
var test = converter.main (test_array[i]);
assert.equal(test, against[i]);
}
for(i = 0; i < 24; i++) {
it(test_array[i] + ' should convert to ' + against[i], callback);
}
})
})
This way each callback
passed to it()
will have access to the arrays without any possibility of them being deleted or altered before testing time.
I don't know mocha at all, so I will defer to Johannes' expert advice on that.
I do have some other suggestions for you though.
First, it will be a real maintenance headache having two arrays running in parallel like test_array
and against
. It's hard to look at those and be sure the right values are matched up.
Instead, put everything into a single array, where each array element contains both test values:
var tests = [
'12:00:00AM = 00:00:00',
'01:00:00AM = 01:00:00',
'02:00:00AM = 02:00:00',
'03:00:00AM = 03:00:00',
'04:00:00AM = 04:00:00',
'05:00:00AM = 05:00:00',
'06:00:00AM = 06:00:00',
'07:00:00AM = 07:00:00',
'08:00:00AM = 08:00:00',
'09:00:00AM = 09:00:00',
'10:00:00AM = 10:00:00',
'11:00:00AM = 11:00:00',
'12:00:00PM = 12:00:00',
'01:00:00PM = 13:00:00',
'02:00:00PM = 14:00:00',
'03:00:00PM = 15:00:00',
'04:00:00PM = 16:00:00',
'05:00:00PM = 17:00:00',
'06:00:00PM = 18:00:00',
'07:00:00PM = 19:00:00',
'08:00:00PM = 20:00:00',
'09:00:00PM = 21:00:00',
'10:00:00PM = 22:00:00',
'11:00:00PM = 23:00:00',
];
You can use split()
in your code to separate the two values in each array element.
Next, never hard code an array length in a for
loop. Instead, if the array is named test
as in my example above, use i < test.length
in the loop. Now if you add or remove entries, the loop will still have the correct length.
However, I wouldn't use a for
loop here at all. You can get cleaner code by using the forEach
array method.
Taking Johannes' code as a starting point, I would change it to:
function itShouldTestTimes( test ) {
var times = test.split( ' = ' );
var time12 = times[0], time24 = times[1];
it( time12 + ' should convert to ' + time24, function() {
var result = converter.main( time12 );
assert.equal( result, time24 );
});
}
describe( 'Time Converter', function() {
describe( 'main()', function() {
tests.forEach( itShouldTestTimes );
});
});
1) BatchTest.js
const assert = require('chai').assert;
const fileOperations = require('../UDRServer/Utility/FileOperations');
var testResultFileName = "TestResult.json";
var data = fileOperations.readFile(testResultFileName);
//console.log(data);
var jsons = data.split('\n');
function runTest(obj) {
describe(obj.name + " Test", function () {
it("Expexted Value " + obj.expectedStatus, function (done) {
assert.equal(obj.expectedStatus, obj.actualStatus);
if (obj.expectedCause != 'null') {
assert.equal(obj.expectedCause, obj.actualCause);
}
done();
})
})
}
describe("Main", function () {
for (let i = 0; i < jsons.length - 1; i++) {
var obj = JSON.parse(jsons[i]);
runTest(obj);
}
});
2 ) FileOperations.js
var readFile = function(filename){
return fs.readFileSync(filename).toString();
}
3) TestResult.json file
{"actualStatus":403,"actualCause":"false","name":"test1","expectedCause":"false","expectedStatus":400}
{"actualStatus":0,"actualCause":"true","name":"test2","expectedCause":"false","expectedStatus":400}
{"actualStatus":400,"actualCause":"false","name":"test3","expectedCause":"false","expectedStatus":400}
{"actualStatus":200,"actualCause":"true","name":"test4","expectedCause":"false","expectedStatus":200}