-
Notifications
You must be signed in to change notification settings - Fork 120
Test Driven Development with Tower
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
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.
Tower.Factory.define 'user', ->
email: Faker.Email
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
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
# ./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")
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>
Use the Mocha BDD interface for Acceptance Testing. The Acceptance Tests can be executed from the console or from within the browser.