Skip to content

Test Driven Development with Tower

Lance Pollard edited this page Oct 9, 2012 · 4 revisions

Test Driven Development (TDD) is a quality of all great apps. Once you master it you're able to not only develop a lot quicker, what you develop is also built on a much stronger foundation and will be more resilient in the face of change.

The problem with TDD, or BDD (Behavior Driven Development) even, is it's hard to get started with. You could spend weeks if not months setting up a solid workflow for building your app around tests. That's why Tower aims to make testing easy and clear.

Tower uses these three libraries for testing:

  • mocha: The async TDD/BDD framework
  • chai: The assertion code to use within mocha tests
  • sinon: A spy/stub/mock framework for testing more advanced/complex code

Build Testable Objects

If your system is at all complex, break out functionality into smaller objects that you can test independently. This is why I broke down Tower "chainable queries" into a Scope and a Criteria object, rather than just having a Scope object. And the reason why there's a distinction between the "model" and "data" (store/datastore) layers.

By doing this, I was able to quickly build out most of the functionality for query generation using just the Criteria object. Then I knew I could get back a hash of conditions and options to use in finding records from a data store.

This makes the whole project more manageable and makes rapid development possible. I found my mind spinning in circles trying to grasp the whole system at once otherwise.

However, note this: there's a tradeoff between testability and performance. If every single thing was built as nested objects like the above two examples, you'd end up creating a ton of objects to do (often) pretty simple things, and this is bad from both a memory and performance standpoint. In most cases it also increases the amount of code you have to write, which more than anything means the browser will have to load more code. So, if something's easy to test without refactoring it into objects, just leave it that way. It's less code for the browser to download, and will most likely use up less memory, which means a better user experience in the end.

Code Coverage

Testing Commands in Tower.js

Testing Controllers in Tower.js

Testing File I/O in Tower.js

Testing Web Sockets in Tower.js

Tower.Factory

Tower.Factory.define 'user', ->
  email: Faker.Email

Fakers

Fakers are used to generate random data.

Faker       = require 'Faker'

randomName  = Faker.Name.findName() # Rowan Nikolaus
randomEmail = Faker.Internet.email() # [email protected]
randomCard  = Faker.Helpers.createCard() # random contact card containing many properties

Testing with Mocha

This command will watch the test directory, and anytime you save a file it will execute the tests.

mocha $(find test -name "*Test.coffee")

You can run it through the node debugger using the -d option:

mocha $(find test -name "*Test.coffee") -d

Testing Models in Tower.js

Example

# ./test/models/userTest.coffee
describe "App.User", ->
  user = null
  
  describe "#fields", ->
    beforeEach (done) ->
      App.User.destroy =>
        user = new App.User
        
    test ".email", ->
      assert.ok user.has("email")

Testing Views in Tower.js

Mocha can be used to "spec" an app including specs for acceptance testing. See the Tower test suite for how to use Mocha to test a Tower app.

The "BDD" interface provides: describe(), it(), before(), after(), beforeEach(), and afterEach(). The "TDD" interface provides: suite(), test(), setup(), and teardown().

To setup Mocha for browser use all you have to do is include the script, stylesheet, tell Mocha which interface you wish to use, and then run the tests. A typical setup might look something like the following, where we call mocha.setup('bdd') to use the BDD interface before loading the test scripts, running them onload with mocha.run().

<html>
<head>
  <meta charset="utf-8">
  <title>Mocha Tests</title>
  <link rel="stylesheet" href="mocha.css" />
  <script src="jquery.js"></script>
  <script src="expect.js"></script>
  <script src="mocha.js"></script>
  <script>mocha.setup('bdd')</script>
  <script src="test.array.js"></script>
  <script src="test.object.js"></script>
  <script src="test.xhr.js"></script>
  <script>
    $(function(){
      mocha
        .globals(['foo', 'bar']) // acceptable globals
        .run()
    })
  </script>
</head>
<body>
  <div id="mocha"></div>
</body>
</html>

Acceptance Testing

Use the Mocha BDD interface for Acceptance Testing. The Acceptance Tests can be executed from the console or from within the browser.

Resources

Clone this wiki locally