Cross-platform, Testable Mobile Goodness with Titanium and Jasmine

  • AUTHOR: truelson
  • January 20, 2011
Cross-platform, Testable Mobile Goodness with Titanium and Jasmine

Phew!  Dogpatch Technology is now simultaneously developing for both iPhone and Android while using an RSpec styled testing framework. Here’s how we do it.

We decided to go with Appcelerator’s Titanium Mobile for our mobile development platform.  Titanium is still a little new, and occasionally throws some wonky behavior at you, but the ability to develop native apps quickly in JavaScript for iPhone and Android simultaneously was just too good to pass up.

But doing so, we had to give up Cedar, a pretty slick RSpec styled testing framework for ObjC written by Pivotal Labs’ Adam Milligan, which was our first introduction to RSpec style BDD coding.  Once we tried BDD, we never wanted to go back.  So when switching to Titanium, we ended up choosing Jasmine, another RSpec styled testing framework for JavaScript, also written by the nice folks at Pivotal Labs.

We found a blog post at Levid Media on how they setup Jasmine for use with Titanium, but it seemed a little out of date and lacking in some key details, so here’s how we set it up on our Snow Leopard dev machine.

Before you start, make sure you’ve installed Jasmine as a ruby gem.  Levid has a quick tutorial on it.  Also make sure you’ve installed the latest Appcelerator Developer Package, have downloaded the latest mobile SDK (1.5.1 as of this post), and have created a new Titanium mobile project for yourself.  Now you’re ready to set up Jasmine as your framework.

First, in the root of your project directory, run:

jasmine init

Your root project directory should look something like:

CHANGELOG.txt LICENSE.txt   Rakefile      build         public        tiapp.xml
LICENSE       README        Resources     manifest      spec

Go ahead and delete the public folder and everything in it as we’re going to be pointing Jasmine at the spec and Resources folder.  Also, delete spec/javascripts/helpers/SpecHelper.js as we aren’t going to need that either. Next we’re going to edit the spec/javascripts/support/jasmine.yml config file.  Here’s a breakdown of ours.

# src_files
# Return an array of filepaths relative to src_dir to include before jasmine specs.
# Default: []
# src_files:
#   - lib/source1.js
#   - lib/source2.js
#   - dist/**/*.js
# *HACK here we're including helper/mock scripts before other source files
- spec/javascripts/helpers/timock.js
- Resources/extras.js
- Resources/ttestmodel.js
- Resources/ttestcontroller.js
- Resources/app.js

Notice that instead of using the helpers directory jasmine offers, I put my Titanium mock class file first before anything else.  The order you specify here is the order the files are loaded, so use this to your advantage, but it is a bit of a hack.   Specifying your helper files in the helper section unfortunately loads them after your class files causing lots of fun javascript errors.

Control of the loading of the javascript files makes writing them a little bit easier to modularize and test them.  Lack of a good way to mimic the Titanium API call “Ti.include” forced us to go this route, and fortunately Jasmine obliges, though I’m sure there may be a better way out there.

# helpers
# Return an array of filepaths relative to spec_dir to include before jasmine specs.
# Default: ["helpers/**/*.js"]
# helpers:
#   - helpers/**/*.js

Notice I left the helper files blank here.

# spec_files
#  Return an array of filepaths relative to spec_dir to include.
# Default: ["**/*[sS]pec.js"]
# spec_files:
#   - **/*[sS]pec.js
    - *[sS]pec.js

We didn’t use any fancy directory structure for our spec files. Just what’s in the spec/javascripts directory.

# src_dir
# Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
# Default: project root
# src_dir: public

We didn’t set src_dir to Resources due to the helper file hack, so left this blank.

# spec_dir
# Spec directory path. Your spec_files must be returned relative to this path.
# Default: spec/javascripts
# spec_dir: spec/javascripts
spec_dir: spec/javascripts

And lastly we tell jasmine where to find it’s javascript specs.  Finally, all we need to do is run from the root project directory:

rake jasmine

And point your browser to http://localhost:8888/ and any spec tests you have will be run.  It’s a heck of a lot easier, especially for Android development to write most of your code using your specs rather than recompiling and launching it from the emulator.

Also it’s relatively easy to set up a hudson continuous integration job that just checks your repository and runs:

rake jasmine:ci

So yes, you CAN do mobile cross platform development with BDD and continuous integration.   Any excuses for not testing your code pointing to how mobile development lacks good cross-platform development tools are just plain wrong.  And I’m sure there are better ways to do it.  Feel free to drop us a line at dev (~at~) with any questions or comments.