Last week at xp-man we did some TDD practise - by writing a tdd framework from scratch. The surprise was, how easy it was. So here, to my surprise, a very-bare-bones javascript unit test framework in 50 lines of code including the passing unit tests for the framework itself.
/* www.cafe-encounter.net/p734/ */ function Specification( name, tests, outputContainer ){ this.name= name; this.tests= tests; this.outputContainer= outputContainer || $('#testResults'); } Specification.prototype = { name : 'UnnamedSpecification', tests : {}, outputContainer : null, addMyselfToUI : function(){ this.outputContainer.append( "<li><h3>" + this.name +"</h3><ul id='" + this.name + "'></ul></li>"); }, testDomId:function (test) { return this.name + "_" + test; }, addTestToUI : function addTestToUI( test ){ $('#' + this.name).append( "<li id='" + this.testDomId(test) + "'>" + test + "<input type='checkbox'/></li>"); }, markTestPassed : function( test ){ $("#" + this.testDomId(test) + " input").prop("checked",true); }, markTestFailed : function( test, ex ){ $("#" + this.testDomId(test) + " input").prop("checked",false); $("#" + this.testDomId(test) + " input").after("<ul>Output:<li>" + ex.toString() + "</li></ul>"); }, runTest : function (test) { this.addTestToUI(test); try{ this.tests[test](); this.markTestPassed(test) } catch(ex) { this.markTestFailed(test, ex); } }, runTests : function(){ this.addMyselfToUI(); for (var test in this.tests) { if (this.tests.hasOwnProperty(test)) this.runTest( test ); } } }; $(function(){ new Specification("TestFrameworkSpecifications", { aTestShouldAddItselfInTheTestResults:function() {}, aPassingTestShouldTickTheCheckbox : function() {}, aFailingTestShouldUntickTheCheckbox:function () { throw "This thrown exception should appear in the output, indicating a failure"; } }).runTests(); });
And the html doc to load and run it:
<html> <head> <title>Minimal Javascript Test Framework</title> <script type="text/javascript" src="js/jquery-1.8.2.js"></script> <script type="text/javascript" src="js/wsl-testframework.js"></script> </head> <body> <h1>Tests</h1> <ul id="testResults"> </ul> </body> </html>
As written, I admit a dependency on jQuery, but you can replace that with document.write(). The obvious omission is a bundle of pre-defined assertions, but if you are developing a domain specific testing language then assertions should be part of that package, not part of the test running framework.
The obvious oddity is that the test suite demonstrates its test failure behaviour by failing a test; and you see that that is the correct result by inspecting the output.
This has led me to think that the TDD way to learn a new language is ... to write a TDD framework for it.