- Although JsUnit has been available since 2001, it's still the love child of a sole developer.
- JsUnit's release schedule is irregular. (Release 2.2 has been in "beta" for over two years now.)
- JsUnit lacks support for direct testing of forms or asyncronous (AJAX) calls.
- While JsUnit is open source, it's distributed under conservative GPL-type licenses, which can discourage other groups from building over the library.
Look Ahead
"YUI Test is a testing framework for browser-based JavaScript solutions. Using YUI Test, you can easily add unit testing to your JavaScript solutions. While not a direct port from any specific xUnit framework,YUI Test does derive some characteristics from nUnit and JUnit."
- Rapid creation of test cases through simple syntax.
- Advanced failure detection for methods that throw errors.
- Grouping of related test cases using test suites.
- Asynchronous tests for testing events and Ajax communication.
- DOM Event simulation in all A-grade browsers.
YUI Test has been available since July 2007 (YUI 2.3.0), and made "GA" grade in February 2008 (YUI 2.5.0). The framework was created by Yahoo! engineer Nicholas C. Zakas. It's regularly released with the rest of the library and distributed under a library BSD license. (Altogether, there seem to be about sixteen developers on the YUI team, maintaining about thirty components). Note that YUI Test can be used to test any JavaScript code -- the application doesn't need to be based on YUI to use YUI Test.
Tripping the Rift
Unit testing conventional, classical code often relies on exercising the "API Contract". If we pass certain parameters to method, the method should return a certain result, or raise a certain exception. Since, JavaScript is event-driven, in order to determine the outcome of a method, we often need to see what event it raises. And, in an Ajax application, there can be a disconnect between when a method is called and then the event is ultimately reaised. YUI Test helps us bridge the gap with a "wait/resume" feature. A test can subscribe to an event, and call "resume" in the event handler. When the test reaches the point where an action might take an indeterminate amount of time, we can call "wait", and the test continues when the event fires.
For example, here's a test that calls a time-consuming animiation routine. The test registers an event handler, starts the animation, and waits for the event to fire. When the animation completes, the test confirms that the routine accomplished the expected result.
<div id="testLogger"></div>
<div id="testDiv" style="position:absolute;width:10px;height:10px"></div>
<script type="text/javascript">
YAHOO.namespace("example.yuitest");
YAHOO.example.yuitest.AsyncTestCase = new YAHOO.tool.TestCase({
name : "Animation Tests",
testAnimation : function (){
var Assert = YAHOO.util.Assert;
var YUD = YAHOO.util.Dom;
var myAnim = new YAHOO.util.Anim('testDiv', { width: { to: 400 } }, 3, YAHOO.util.Easing.easeOut);
myAnim.onComplete.subscribe(function(){
this.resume(function(){
Assert.areEqual(YUD.get("testDiv").offsetWidth, 400, "Width of the DIV should be 400.");
});
}, this, true);
// Start the animation and wait for the resume function
myAnim.animate();
this.wait();
}
});
YAHOO.util.Event.onDOMReady(function (){
var logger = new YAHOO.tool.TestLogger("testLogger");
YAHOO.tool.TestRunner.add(YAHOO.example.yuitest.AsyncTestCase);
// Run the tests when DOM is ready
YAHOO.tool.TestRunner.run();
});
</script>
Not every test needs to use wait/resume, but, when we do, it's an indispensible feature.
Be Assertive
<script type="text/javascript">var oTestCase = new YAHOO.tool.TestCase({name: "TestCase Name",testEqualityAsserts : function () {var Assert = YAHOO.util.Assert;Assert.areEqual(5, 5); //passesAssert.areEqual(5, "5"); //passesAssert.areNotEqual(5, 6); //passesAssert.areEqual(5, 6, "Five was expected."); //fails}});</script>
<script type="text/javascript">var oTestCase = new YAHOO.tool.TestCase({name: "TestCase Name",testSamenessAsserts : function () {var Assert = YAHOO.util.Assert;Assert.areSame(5, 5); //passesAssert.areSame(5, "5"); //failsAssert.areNotSame(5, 6); //passesAssert.areNotSame(5, "5"); //passesAssert.areSame(5, 6, "Five was expected."); //fails}});</script>
<script type="text/javascript">var oTestCase = new YAHOO.tool.TestCase({name: "TestCase Name",testTypeOf : function () {var Assert = YAHOO.util.Assert;Assert.isTypeOf("string", "Hello world"); //passesAssert.isTypeOf("number", 1); //passesAssert.isTypeOf("boolean", true); //passesAssert.isTypeOf("number", 1.5); //passesAssert.isTypeOf("function", function(){}); //passesAssert.isTypeOf("object", {}); //passesAssert.isTypeOf("undefined", this.blah); //passesAssert.isTypeOf("number", "Hello world", "Value should be a number."); //fails}});</script>
Push the Envelope
- User Actions are simulated user-initiated events that can be used to test how scripts react to mouse or keyboard events.
- Asyncronous Tests can be programmed to pause for a certain amount of time (while an out of process action occurs), or to pause until an event handler in the test script calls a "resume" method.
More about YUI Test
- Writing Your First YUI Application, Eric Miraglia (2008 May).
More about JsUnit
- AJAX and Unit Testing - it's time to mingle, Jim Plush (2006 Feb),
- Ajax and Unit Testing Part Two, The Wrath of Mock, Jim Plush (2006 Nov).