We work with the Ruby on Rails web application framework frequently for our clients.
Just like any other tool, we like to reflect on how we can use Rails better every day. The following are some of the practices we feel help us develop our applications more responsibly and efficiently.
Be Developer-Testers
Built-in, up-front support for testing is a major attraction to Rails. Think like a tester while writing tests. This means more than just Test-Driven Development. It means using exploratory, creative, and effective test strategies. It means trying hard to break the software in testing so that you know it won’t fail in the wild.
- Have your customers write an acceptance test for a feature.
- Write an integration test that initially fails.
- Write functional and unit tests respectively, iteratively driving the actual code with passing tests.
- See the tests pass in the reverse order as above.
Build a testing language on the fly
Ruby is a great language for building abstractions and Rails itself is perhaps the best example. So don’t just take what comes with the framework to build web applications. Write Domain-Specific Languages as you go. Use your skills as a toolsmith to make testing and development easier, faster, and more accurate with less work. This usually means defining a language with the customers and then building a language bridge to the business domain encompassed by the language.
Story-Driven Development
SDD reduces the risk of delivering the wrong software.
When you mix testing and domain specific languages you get story-driven development. Extreme Programming lets us replace requirement elicitation with story gathering. When you let your customers write stories before you write code, you can drive features with executable requirements. The customer can always see exactly what is done because the tests run against the real system and show exactly what the customer asked.
See “User Stories Applied For Agile Software Development” by Mike Cohn
Tools and Tricks
Even the most skilled toolsmiths need good tools.
The Rails community is rich with involved developers who give their efforts back to their fellow developers. Here’s our list of essential tools on every Rails site we craft. Some we’ve written in-house and some are from the community at large.
Routes testing (example)
How would your Rails application function if you removed or broke some of its routes? Rails gives you assert_routing. Use it to test every route in the routes file.
- test drive your schema modifications and additions with assert_schema
- make sure you can migrate from 0 to latest, and back again. After all, if the code’s in source control, it should be working, right?
- verify that data transformation migrations work as expected
Validation testing (example)
Rails provides easy-to-use validation support. Don’t let that stop you from testing these critical parts of a web application.
Testing forms in integration and functional tests can get complicated. The form_test_helper plugin makes quick work of asserting a form contains certain inputs, and submitting a form with given values for those inputs:
submit_form do |f| f.post.title = 'My New Post' f.post.body = 'This is my best post ever!!' end
assert_select (cheatsheet)
As of rails 1.2.1 assert_select is the preferred method of testing rendered html templates and partials in a rails application. Rendered content and document structure can be verified using css selectors and dug into by nesting assert_select calls within blocks.
assert_select_rjs is very helpful for verifying rendered partials which are being used for replace, replace_html or insert_html RJS calls.
Use RJS and ARTS so that fancy AJAX behaviors can be nailed down and asserted in tests. Don’t let the complex nature of interactive DOM manipulation get in the way of quality assurance.
We wrote a simple Ruby package that adds a taste of behavior-driven development without radically changing Rails’ testing mechanism. Behaviors turns Test::Unit test methods into plain English descriptions of app functionality. A simple Rake task lets you list those tests as a reference for all the things the code under test can do.
HardMock
Use mock objects for interaction-based testing. Written at Atomic Object, HardMock is our favorite among many choices for Ruby mock object libraries because of its simplicity and expressiveness.
Injection Plugin
Injection is a simple dependency injection plugin for Rails. Injection allows you to have objects injected into your controllers which can be easily replaced by mocks in functional tests. We often use Injection to hide details of complex logic which needs to be invoked in an action of a controller. Some examples include:- parsing, validating and saving an uploaded file
- interacting with a payment gateway service
- building a complicated report data structure which needs to be rendered
Jay Fields’s version of a Presenter in rails is aimed at solving the same problems mentioned above by taking the step of moving the complex functionality into another class to allow better testability.
rcov
rcov is a code coverage tool for Ruby written by Mauricio Fernandez. Use it to make sure every line of application code is covered in your tests.
Updated on Jan 23, 2007