Arieh.co.il

Introducing Moock

JS TDD

I've spent the last couple of days fiddling around with JS TDD, using the awesome JsTestDriver. It's a great tool, allowing very easy-to-use tools for TDD across several browsers all at once. What's more, is that it has a very useful (and partially stable) Eclipse plugin.

What it lacks, as far as I've noticed, is a solid mocking API. This is something that PHPUnit does really well, and I was really missing writing my tests. So, as an exercise in testing, I've written one.

Moock - a test-suite agnostic JS stubbing library

What started as a very small Mootools excercise, ended up as a full, cross-environment Stubbing tool. It started with a simple function replacement tool. It's usage was quite simple - you created a stub, passing it a value to return when called. You would then receive a function with some extra properties:

  1. used - a number indicating how many times the function was used.
  2. args - an array containing the last group of variables that were passed to the stub.

With these in mind, we get this simple use case:

This is fine, and by itself can be all that we need. But I wanted more. If you've used PHPUnit's mock object, you should be familiar with the way you can use it to define expectations. Writing such an API by itself shouldn't be a very difficult job - but it posed a problem for the cross-lib principle - Writing expectations means writing assertions into the Stub itself, and each library has it's own way of writing assertions.

And so I had to come up with a way to create a method for writing cross-library assertions - and thus came to be Moock.Assert. What I did is I've implemented an API (using the Decorator Pattern) for running assertions. It is made out of two parts:

  1. Moock.Assert: containing a wrapping API for writing assertions. It currently provides Moock.Assert.isTrue(expression,message) and Moock.Assert.areEqual(expected,actual,message).

  2. Moock.Libraries: this is where the cool stuff happens - this is a collection of objects that tell the Assert mechanism how to call each library's assertions. For example, the QUnit wrapper looks like this:

            Moock.Libraris.QUnit = {
                check : !!(window.QUnit)
                , isTrue : function(expr,msg){
                    QUnit.ok(expr,msg);
                }
                , areEqual : function(expect,actual,msg){
                    QUnit.equal(actual,expect,msg);
                }
            };
            

    Each library needs to supply 2 main parts: check - Some rule to tell the Moock whether the library is present, and assertion functions that correspond to the assertions found in Moock.Assert.

The result

With all the above in mind, I've been able to provide the following syntax:

A few notes:

  1. Notice the test method in the end - this is where the object checks if it was called like it was expected.
  2. Since we're only console.loging, we're missing some of the logic, but the logged arrays means it should compare the 2 arrays, and the numbers mean that it should compare how many times the function was called.
  3. The aaa means that the function did indeed return the correct string.

But there's more! The Mootools twist

As I mentioned earlier, the entire excercise was about creating mock objects. I wanted to create a Mutator for Class, that will provide a tool for real decoupling for Class TDD. The result looks like this:

Note that I wrote the tests so they will fail, so you should see some failure messages.

Links

  1. Moock on github.
  2. Moock on the Forge.
  3. JsTestDriver on google pages.
JavaScript Reference, JavaScript Guide, JavaScript API, JS API, JS Guide, JS Reference, Learn JS, JS Documentation