Evidence is a new, framework-agnostic unit testing library which I developed out of necessity and frustration with the existing offering. Although it's heavily inspired by it's Ruby, Python and Java couterparts, Evidence is packed with niceness targeted at the specificities of the JavaScript language and its different environments. Hopefully this introduction to Evidence will give you the motivation, tools and knowledge to start unit testing your JavaScript code if you are not doing so already.
11. A lot of unit tests (> 2000 assertions).
Complex cases (async, cross-browser).
12. A lot of unit tests (> 2000 assertions).
Complex cases (async, cross-browser).
Uses a framework originally created in
2005 for script.aculo.us...
13. A lot of unit tests (> 2000 assertions).
Complex cases (async, cross-browser).
Uses a framework originally created in
2005 for script.aculo.us...
...with a dependency on Prototype.
45. function callAssertions(fn) {
var rgxp = /^[^{]*{((.*n*)*)}/m;
fn = fn.toString();
fn = fn.match(rgxp)[1];
eval('with (dsl) {
with (context) {
with (matchers) { ' +
fn + ' }}}');
}
46. Function decompilation
function callAssertions(fn) {
(Not part of any standard.)
var rgxp = /^[^{]*{((.*n*)*)}/m;
fn = fn.toString();
fn = fn.match(rgxp)[1];
eval('with (dsl) {
with (context) {
with (matchers) { ' +
fn + ' }}}');
}
47. function callAssertions(fn) {
var rgxp = /^[^{]*{((.*n*)*)}/m;
fn = fn.toString();
fn = fn.match(rgxp)[1];
eval('with (dsl) {
with (context) {
with (matchers) { ' +
fn + ' }}}'); Nested with statements
} (Not ES5 strict compliant.)
48. function callAssertions(fn) {
var rgxp = /^[^{]*{((.*n*)*)}/m;
fn = fn.toString();
eval
fn = fn.match(rgxp)[1];
(Not supported in some environments.)
eval('with (dsl) {
with (context) {
with (matchers) { ' +
fn + ' }}}');
}
49. function callAssertions(fn) {
var rgxp = /^[^{]*{((.*n*)*)}/m;
fn = fn.toString();
fn = fn.match(rgxp)[1];
eval('with (dsl) {
with (context) {
with (matchers) { ' +
fn + ' }}}');
}
58. var ArrayTest = Evidence.TestCase.extend('ArrayTest', {
setUp: function() {
this.array = ['foo', 'bar', 'baz'];
},
testFirst: function() {
this.assertEqual('foo', _.first(this.array));
this.assertUndefined(_.first([]));
},
testLast: function() {
this.assertEqual('bar', _.last(this.array),
'Failed to grab the last element of the array.');
this.assertUndefined(_.last([]));
}
});
59. var ArrayTest = Evidence.TestCase.extend('ArrayTest', {
setUp: function() {
this.array = ['foo', 'bar', 'baz'];
},
“Subclass” TestCase
testFirst: function() {
this.assertEqual('foo', _.first(this.array));
this.assertUndefined(_.first([]));
},
testLast: function() {
this.assertEqual('bar', _.last(this.array),
'Failed to grab the last element of the array.');
this.assertUndefined(_.last([]));
}
});
60. var ArrayTest = Evidence.TestCase.extend('ArrayTest', {
setUp: function() {
this.array = ['foo', 'bar', 'baz'];
},
Give it a name.
testFirst: function() {
this.assertEqual('foo', _.first(this.array));
this.assertUndefined(_.first([]));
},
testLast: function() {
this.assertEqual('bar', _.last(this.array),
'Failed to grab the last element of the array.');
this.assertUndefined(_.last([]));
}
});
61. var ArrayTest = Evidence.TestCase.extend('ArrayTest', {
setUp: function() {
this.array = ['foo', 'bar', 'baz'];
},
testFirst: function() {
Add fixtures to your _.first(this.array));
this.assertEqual('foo',
setUp method.
this.assertUndefined(_.first([]));
},
testLast: function() {
this.assertEqual('bar', _.last(this.array),
'Failed to grab the last element of the array.');
this.assertUndefined(_.last([]));
}
});
62. var ArrayTest = Evidence.TestCase.extend('ArrayTest', {
Prefix setUp:testcases {with
your function()
this.array = ['foo', 'bar', 'baz'];
}, test.
testFirst: function() {
this.assertEqual('foo', _.first(this.array));
this.assertUndefined(_.first([]));
},
testLast: function() {
this.assertEqual('bar', _.last(this.array),
'Failed to grab the last element of the array.');
this.assertUndefined(_.last([]));
}
});
63. var ArrayTest = Evidence.TestCase.extend('ArrayTest', {
setUp: function() {
this.array = ['foo', 'bar', 'baz'];
},
testFirst: function() {
this.assertEqual('foo', _.first(this.array));
this.assertUndefined(_.first([]));
},
testLast: your assertions.
Write function() {
this.assertEqual('bar', _.last(this.array),
'Failed to grab the last element of the array.');
this.assertUndefined(_.last([]));
}
});
64. var ArrayTest = Evidence.TestCase.extend('ArrayTest', {
setUp: function() {
this.array = ['foo', 'bar', 'baz'];
},
testFirst: function() {
this.assertEqual('foo', _.first(this.array));
this.assertUndefined(_.first([]));
},
testLast: function() {
this.assertEqual('bar', _.last(this.array),
'Failed to grab the last element of the array.');
this.assertUndefined(_.last([]));
}
Optionally add
}); meaningful error
messages.
67. Evidence.TestCase.extend('AjaxTest', {
testAjaxRequest: function(testcase) {
testcase.pause();
new Ajax.Request('/some/url', { instance
TestCase
onComplete: function(response) {
conveniently passed as a
testcase.resume(function() {
this.assert(response); first argument.
});
}
});
}
});
68. Evidence.TestCase.extend('AjaxTest', {
testAjaxRequest: function(testcase) {
No need to bind this or
testcase.pause();
create your own closure.
new Ajax.Request('/some/url', {
onComplete: function(response) {
testcase.resume(function() {
this.assert(response);
});
}
});
}
});
69. Evidence.TestCase.extend('AjaxTest', {
testAjaxRequest: function(testcase) {
testcase.pause();
new Ajax.Request('/some/url', {
onComplete: function(response) {
testcase.resume(function() {
this.assert(response);
});
Bound to the original
}
}); scope so:
} this === testcase
});
71. function getTestCaseNames(testcaseClass) {
var results = [];
for (var property in testcaseClass.prototype) {
if (property.indexOf('test') === 0) {
results.push(property);
}
}
return results.sort();
}
72. Grab all the methods
function getTestCaseNames(testcaseClass) {
var results = []; starting with test.
for (var property in testcaseClass.prototype) {
if (property.indexOf('test') === 0) {
results.push(property);
}
}
return results.sort();
}
73. function getTestCaseNames(testcaseClass) {
var results = [];
for (var property in testcaseClass.prototype) {
if (property.indexOf('test') === 0) {
results.push(property);
} Sort the results.
}
return results.sort();
}
74. function loadTestsFromTestCase(testcaseClass) {
var suite = new TestSuite(testcaseClass.displayName),
methodNames = getTestCaseNames(testcaseClass);
for (var i = 0; i < methodNames.length; i++) {
suite.push(new testcaseClass(methodNames[i]));
}
return suite;
}
75. Create a new suite.
function loadTestsFromTestCase(testcaseClass) {
var suite = new TestSuite(testcaseClass.displayName),
methodNames = getTestCaseNames(testcaseClass);
for (var i = 0; i < methodNames.length; i++) {
suite.push(new testcaseClass(methodNames[i]));
}
return suite;
}
76. Give it a name.
function loadTestsFromTestCase(testcaseClass) {
var suite = new TestSuite(testcaseClass.displayName),
methodNames = getTestCaseNames(testcaseClass);
for (var i = 0; i < methodNames.length; i++) {
suite.push(new testcaseClass(methodNames[i]));
}
return suite;
}
77. function loadTestsFromTestCase(testcaseClass) {
var suite = new TestSuite(testcaseClass.displayName),
methodNames = getTestCaseNames(testcaseClass);
for (var i = 0; i < methodNames.length; i++) {
suite.push(new testcaseClass(methodNames[i]));
}
Grab the testcase names.
return suite;
}
78. function loadTestsFromTestCase(testcaseClass) {
var suite = new TestSuite(testcaseClass.displayName),
methodNames = getTestCaseNames(testcaseClass);
for (var i = 0; i < methodNames.length; i++) {
suite.push(new testcaseClass(methodNames[i]));
}
return suite; Create a new instance of
}
the testcase class.
79. function loadTestsFromTestCase(testcaseClass) {
var suite = new TestSuite(testcaseClass.displayName),
methodNames = getTestCaseNames(testcaseClass);
for (var i = 0; i < methodNames.length; i++) {
suite.push(new testcaseClass(methodNames[i]));
}
return suite;
Add it to your suite.
}