Test-Driven Development
We use Test-Driven Development as development methodology. TDD is, according to TestDrivenDevelopment by Martin Fowler,
- Write a test for the next bit of functionality you want to add.
- Write the functional code until the test passes.
- Refactor both new and old code to make it well structured. You continue cycling through these three steps, one test at a time, building up the functionality of the system.
We write our tests as specifications using RSpec, a tool which allows us to automatically run the test suite through a command line interface.
Specifications
We usually write two types of specifications, feature and class specifications.
Feature Specifications
Feature specifications are end-to-end specifications written from the user perspective which, when executed, exercise the entire application stack. This type of specifications is written only for application with a user interface. For applications which don’t require user interaction, we write a different kind of end-to-end specifications.
An example of a feature specification is
Without going into too many details1, the specification describes how the application is supposed to work (when a user tries to log into the application providing a valid password he is redirected to the homepage) and verifies it by simulating the user interaction (filling out forms, clicking buttons and so on) and then asserting on the application state.
We normally write a single specification (with multiple scenarios) for each issue we develop. Each scenario confirms a specific condition of satisfaction associated with the Issue.
Class Specifications
Class specifications (also called unit tests) are lower-level specifications which individually and independently verify the correctness of a single class.
An example of a class specification is
The specification describes the invalidity of, and therefore the impossibility to save into the database, a user without a full name.
Class specifications are focused on a single class and instances of that class thus they are executed in isolation. This means when interaction with other classes or objects is required, those interactions are often mocked2.
We normally write a single specification (with multiple examples) for almost each class we have in our applications3. Each example verifies a specific method defined within the class.
#####Notes:
- For more details regarding RSpec syntax refer to the documentation.
- Mock objects are simulated objects that mimic the behavior of real objects in controlled ways
- For a typical Rails application, we skip specifications only for controllers which are indirectly tested with feature specifications, and validators which are tested within the model they validate.