Showing posts with label coffeescript. Show all posts
Showing posts with label coffeescript. Show all posts

Saturday, April 20, 2013

Jasmine Tips: Spies!

We Started using Jasmine for JavaScript testing about 4 months ago. It was chosen because it resembles rspec, and lately minimizing context shift has been a goal for our team. So far I really like Jasmine. There are however, some cases that can be frustrating for someone new to unit tests with JavaScript or Jasmine.

Undersanding spyOn

One of the most important parts of Jasmine tests is understanding spies. I use spyOn because jasmine.spy is a long string to type. Spies can be confusing initially, but they are very useful. Their primary function is to check that a specific method is called, but they can also be used for stubbing.
What spy does is replace the argument with a function that tracks function calls. This means that the replaced function will not be called, the spy has taken its place.

This can be useful when testing objects that involve form submissions, it prevents a situation where your test browser keeps submitting and never finishes the suite.

andCallThrough()

You might want the method being spied on to be called as well. Sometimes not doing so will cause an exception. This is easy to do.

andReturn()

It is also possible to force the spy to return a specific value. This can be useful for stubbing external methods and testing how your code responds based on external conditions, withought going through the trouble of causing those changes. It also helps keep the unit tests isolated, which is very good.

andCallFake()

For testing callbacks it is possible to mock a response, and make sure the correct responses are triggered for different cases. The below example is a little long. But what is happen is that andCallFake is used to make sure that the correct callbacks are used to respond to save success and failure.

Checking Events

A common test I will write is to make sure that an event is getting fire when a method is called. For this you want to use a spy. I usually use spyOn for this. The important pattern to remember is.
  1. spy
  2. bind
  3. trigger event
  4. expect
The first step is to spy on the event you expect to be trigger. Next, if necessary, bind your spy to the event. Trigger that event. And then expect the spy to have been called.

Another option for the case above would be to spy on the model's trigger method. This has the benefit of terseness. It also requires testing the arguments. This can be done simply

Nick hates the word "Gotchas!", I agree

The spy, bind, trigger, expect pattern is simple enough. But when the object being spec'd is doing the binding the patter can be more difficult to grasp. Look at the below example.

This will fail, because spyOn replaces the reference to the function with a spy, but the original method has already been bound to the event. The pattern above is: bind, spy, trigger, expect. It will not work. I like to fix this by splitting event binding out of the initiaize method.

The above code will pass because the spy has been bound to the event. And you can see that it has taken on the form of spy, bind, trigger, expect.
In general it is a good do as little as possible directly in the constructor (initialize for backbone classes). This makes the code more testable. And writing testable code is good.

Conclusion

Spies are awesome. They are kinda a Swiss Army knife of Jasmine testing. Its a straightforward way of solving a lot problems associated with unit testing (stubbing, mocking, testing events). They can be tricky, but with a little experience they can be very useful.

Sunday, April 14, 2013

Why I'm using Coffeescript... For Now

To put it mildly, JavaScript has some idiosyncrasies. I've enjoyed manipulating, and exploiting some of JavaScript's more interesting aspects. However, it's uniqueness can cause confusion. It is perfectly fine to those with experience with JavaScript, but they often trip up even experience programmers that aren't well versed in the language.

Concerns about debugging

One major advantage of JavaScript development is how well debugging is integrated. Chrome and now Firefox debugging is pretty awesome. The only comparable interfaces I've used are Eclipse and XCode, and Chrome preforms better than either of these.
Initially I was concerned that the change in syntax and line numbers would make debugging difficult. Put simply, this turns out to this is much less of an issue than I anticipated. It is trivial to identify corresponding CoffeeScript code working backward from compiled JavaScript.

Class creation

It starts with simple class creation. In JavaScript there isn't anything to distinguish a Class from any other named function.
var MyClass = function(){};
That is, until you add methods to it.
MyClass.prototype.foo = function(){};
This is just weird.
CoffeeScript makes it a little more clear what is a class.
class MyClass   
    foo: ->

Which this is this

Here's a common scenario. I want to bind an instance method of an object to listen to an event (Mouse Click, AJAX response whatever). In java script I have to store this in a local variable so that I can use it later. Looks something like this.
var MyClass = function(){
    var t = this;
    $("a.bindo").click(function(){
        t.onClick();
    })
}

MyClass.prototype.onClick = function(){
    console.log("This is me", this);
}
I've used that pattern hundreds of time. It is useful, but again confusing to someone new to the language. The CoffeeScript version, by contrast, is succinct.
class MyClass   
    constructor: ->
        $("a.bindo").click @onClick

    onClick: => 
        console.log("This is me", @)
It is true that the developer has to understand on a conceptual level what is happening with the bind event, but I find that a simple character difference is more readily accessible and apparent than the JavaScript pattern.

Inheritance

CoffeeScript inheritance murders JavaScript inheritance. I have an older post on JavaScript prototype inheritance. It works (kinda), but again is unfamiliar to people coming from other languages.
CoffeeScript inheritance is easy, and offers something I've not seen cleanly executed in raw JavaScript. The super keyword in CoffeeScript called the super
in JavaScript to call the parent method it looks something like this.
var MyClass = function(){
    ParentClassName.call(this, arguments)
}
Now I think call and apply are super dope, but most of the time I would prefer to never touch them. Now the CoffeeScript equivalent
class MyClass extends ParentClassName
    constructor: ->
        super
That's is way easier, and way less likely to cause hard to track down bugs.

Integration with Ruby stack

In the 12 months we moved over to a Ruby stack after spending a long neolithic era using PHP. It is very easy to integrate CoffeeScript into an application using several Ruby frameworks including: Rails, Sinatra, and Serve. Not having to do any extra work to integrate CoffeeScript was a huge plus!

Dart

Dart looks awesome and I'll be following its progress, once it is supported by a couple major browsers (not just compiled to JavaScript), I'll be more than happy to give it a serious look. Strong typing and isolates are enough reason for serious consideration.

Conclusion

CoffeeScript isn't perfect. And I'm looking forward to new languages to come out for the browser platform. But the bottom line is productivity. And right now, for me and our team, CoffeeScript has a few key features that make web client dev less of a grind, while allowing us to leverage our JavaScript knowledge.