<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><p style="margin: 0px 0px 16px; color: rgb(50, 51, 51); "><p style="font-size: 12px; font-family: Helvetica; margin: 0px 0px 16px; "><div style="margin: 0px; font-family: Georgia; "><div style="margin: 0px; ">The thing I always do when I encounter a large code base, is roam though it and make a mental map of the structure; the good parts and ones that would benefit from some TLC.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">A part I noticed did not yet receive the amount of attention it deserves are unit tests and asynchronous code handling.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">I'll be blunt about it, here's what I did: I ported the <span style="font-family: Courier; ">async</span> NodeJS library to a Mozilla-style module and on top of that I built a unit testing framework, inspired by Mocha (among others).</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">I can imagine that the fellas I just mentioned don't make you recall anything, so here are two links:</div>
<ul>
<li style="margin: 0px; "><a href="https://github.com/caolan/async">https://github.com/caolan/async</a></li>
<li style="margin: 0px; "><a href="https://github.com/visionmedia/mocha">https://github.com/visionmedia/mocha</a></li>
</ul><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">First of all, the Github numbers will show you that they are crazy popular NodeJS libraries. And well-documented. And well-written. And awesome.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">Here's the thing I ended up with: <a href="https://github.com/mikedeboer/mozAsync">https://github.com/mikedeboer/mozAsync</a></div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">The <span style="font-family: Courier; ">lib</span> folder therein contains two files:</div>
<ul>
<li style="margin: 0px; ">Async.jsm - the port of the <span style="font-family: Courier; ">async</span> library</li>
<li style="margin: 0px; ">AsyncTest.jsm - the unit testing library</li>
</ul><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">The <span style="font-family: Courier; ">test</span> folder contains the unit tests (erm, duh) and also serve as great examples of how to use the two modules!</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">Ok, example time! I really like this one from the <span style="font-family: Courier; ">async</span> module:</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; font-family: Courier; ">// Sorts a list by the results of running each value through an async iterator.</div><div style="margin: 0px; font-family: Courier; ">Async.sortBy(["file1", "file2", "file3"], function(file, callback){</div><div style="margin: 0px; font-family: Courier; "> fs.stat(file, function(err, stats){</div><div style="margin: 0px; font-family: Courier; "> callback(err, stats.mtime);</div><div style="margin: 0px; font-family: Courier; "> });</div><div style="margin: 0px; font-family: Courier; ">}, function(err, results){</div><div style="margin: 0px; font-family: Courier; "> // results is now the original array of files sorted by</div><div style="margin: 0px; font-family: Courier; "> // modified date</div><div style="margin: 0px; font-family: Courier; ">});</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">Note: this one uses a NodeJS API, but you can mentally replace that with an async MozFile one.</div><div style="margin: 0px; ">I've told some of you before that I'm not a big fan of Promise libraries (if not, please read the 10 reasons to NOT use a Promise library: <a href="https://gist.github.com/mikedeboer/5305020">https://gist.github.com/mikedeboer/5305020</a>). However, this library is not meant to replace them, but to augment the ecosystem with another option. There are many developers out there that feel uneasy about using Promises as long as they're not a first-class primitive in SpiderMonkey.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">If that's you, you can use this: a minimalistic, functional utility library.</div><div style="margin: 0px; font-size: 16px; min-height: 19px; "><br></div><div style="margin: 0px; text-align: center; font-size: 21px; font-family: 'Helvetica Neue'; "><b>What about them unit tests?</b></div><div style="margin: 0px; "><br></div><div style="margin: 0px; ">Design goal: create a simple, minimalistic framework that provides a clear, unified API to create unit tests that is as easy to use for sync code flows as for async ones.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">Rationale: unit tests are 'hot' code. They are modified as often - perhaps even more - as functionality it covers changes, especially in TDD environments. They serve as documentation for the code they cover. When tests fail, they usually don't on 'your computer', but somewhere else, like on the build infrastructure. When that happens, someone will open the unit test and try to understand what is going on. In all these cases it is hugely beneficial to a) know that most of the unit tests are written in the same structure and b) are structured in such a way that they're easy to read by someone other than you.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">This is an example of a minimal test:</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; font-family: Courier; ">AsyncTest([</div><div style="margin: 0px; font-family: Courier; ">{</div><div style="margin: 0px; font-family: Courier; "> name: "Minimal Test",</div><div style="margin: 0px; font-family: Courier; "> reporter: "tap",</div><div style="margin: 0px; font-family: Courier; "> tests: {</div><div style="margin: 0px; font-family: Courier; "> "it should execute this test": function(next) {</div><div style="margin: 0px; font-family: Courier; "> Assert.equal(typeof next, "function", "'next' should be a callback function");</div><div style="margin: 0px; font-family: Courier; "> next();</div><div style="margin: 0px; font-family: Courier; "> },</div><div style="margin: 0px; font-family: Courier; "> "! it should NOT execute this test": function(next) {</div><div style="margin: 0px; font-family: Courier; "> Assert.ok(false, "BAM!");</div><div style="margin: 0px; font-family: Courier; "> next();</div><div style="margin: 0px; font-family: Courier; "> },</div><div style="margin: 0px; font-family: Courier; "> "it should be aware of the correct context": function() {</div><div style="margin: 0px; font-family: Courier; "> Assert.ok(this["it should execute this test"], "The function ought to be accessible");</div><div style="margin: 0px; font-family: Courier; "> }</div><div style="margin: 0px; font-family: Courier; "> }</div><div style="margin: 0px; font-family: Courier; ">}</div><div style="margin: 0px; font-family: Courier; ">]);</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">There are a couple of interesting things going on here:</div>
<ul>
<li style="margin: 0px; ">You can pass an Array of test suites or just one Object</li>
<li style="margin: 0px; ">Suites can have names</li>
<li style="margin: 0px; ">Tests can be described freely</li>
<li style="margin: 0px; ">It mixes fine with ANY assertion style (Mochi or XPCShell)</li>
<li style="margin: 0px; ">Prefix a test with <span style="font-family: Courier; ">!</span> to exclude it from the suite</li>
<li style="margin: 0px; ">Prefix a test with <span style="font-family: Courier; ">></span> to only run that test and ignore the others</li>
<li style="margin: 0px; ">If the test is sync, you can forget about the <span style="font-family: Courier; ">next</span> function (callback) completely - the framework takes care of it; you can even mix async and non-async tests</li>
<li style="margin: 0px; ">You can choose the style of reporting by setting the <span style="font-family: Courier; ">reporter</span> property to <span style="font-family: Courier; ">dot</span> or <span style="font-family: Courier; ">tap</span>. The reporters <span style="font-family: Courier; ">progress</span> and <span style="font-family: Courier; ">spec</span> are under development. More information about what 'TAP' is can be found at: <a href="http://testanything.org">http://testanything.org</a></li>
</ul><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">But more importantly, there are several things that usually need to happen before a test can be run, like opening a tab, load a page and wait for it to load, etc. AsyncTest unifies scenarios like this in the following way:</div>
<ul>
<li style="margin: 0px; ">Each suite may have one or more of the following functions:</li>
<ul>
<li style="margin: 0px; ">setUpSuite - run only once before any test is executed</li>
<li style="margin: 0px; ">setUp - run once before each test</li>
<li style="margin: 0px; ">tearDownSuite - run only once when all tests are done</li>
<li style="margin: 0px; ">tearDown - run once after each test</li>
</ul>
<li style="margin: 0px; ">These functions are executed in the context of the tests, so the <span style="font-family: Courier; ">this</span> is the same as the <span style="font-family: Courier; ">this</span> in test functions</li>
</ul><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">This takes care of all the flows a test suite might need to implement.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">To top this off, you can set a flag in each suite: <span style="font-family: Courier; ">notify: true</span> to present you with a Growl notification once the suite is done to report the results!</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">That shows that this library is meant to bring back the fun into creating unit tests.</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">Have fun and please let me know what you think!</div><div style="margin: 0px; min-height: 14px; "><br></div><div style="margin: 0px; ">Mike.</div><div><br></div></div></p></p></body></html>