Posted by Matt on Nov 13, 2009
Sharing Knowledge
On my vacation this week, I had the fortune of talking with some developers about Ruby development. During these conversations, I had the joy of introducing some people to some new Ruby tools for rapid application development and testing.
Before I get into that, I wanted to quickly talk about sharing knowledge. Share whenever possible. It doesn’t matter if its about a programming language, some library, tips, or tricks. The littlest thing can open whole new concepts or generate great ideas.
For today’s blog, I’d like to share some tools and tips I use for Rapid Application Development and Rails Unit Testing.
Rapid Application Development
One thing I talked about was rapidly putting together a website or web based API to test a concept or demonstrate functionality. While some people use Rails, I find that I can use a Sinatra stack much more quickly.
When putting together a concept site, I like to use Sinatra, HAML/Sass, JQuery, DataMapper, and SQLite.
For most of the apps I build for fun or test a concept, I find that Rails is overkill. I only need a few routes and a few views, so for me, Sinatra fits the bill. I can put all of my routes in a single file and all of my views in a single views/ folder.
JQuery and HAML/SASS are solely my preference. I find that I write my markup and styles in HAML & SASS faster than if I write them in HTML and CSS. I also find that JQuery selectors pairs up nicer with the markup I write in HAML.
I like using DataMapper connecting to a SQLite3 in-memory database. I’ve seen several example of this with Sinatra and think its brilliant. Since DataMapper lets you define the schema for your database in the models, you can generate a new database everytime your app is loaded by setting up the database connection to a memory database in the Sinatra ‘configure’ block and then calling DataMapper.auto_migrate!.
# lib/pet.rb class Pet property :id, Serial property :name. String end # app.rb require 'rubygems' require 'sinatra' require 'dm-core' require 'lib/pet' configure do DataMapper.setup(:default, 'sqlite3::memory:') DataMapper.auto_migrate! end get '/' ... end ...
Rails Unit Testing
Nothing against RSpec, but it’s just not my cup of tea. I prefer Test::Unit, but I augment it with several libraries.
First and foremost, I always add in Shoulda. Shoulda allows you to set contexts (to group similar tests and setup test data) and has several assertions that, among others, simplify testing redirects and model associations.
Next up are FactoryGirl and aiwilliams-dataset.
Even though foxy fixtures made fixtures less brittle, they can still be problematic to work with. Fixtures map back to database inserts so none of those lovely model filters will get hit when the record is created. As an example, a fixture for a User model would need you the developer to set the crypted password manually instead of having the model generate it on creation. This is where FactoryGirl comes into play. FactoryGirl allows you to define a Factory object which generates a new Object with default values through the Object’s create method. In this example, the Factory for a User would have a default password and password_confirmation that would get crypted at creation.
Factory.define :user do |u| u.login 'george' u.password 'pass123' u.password_confirmation 'pass123' end Factory.define :car do |c| c.model 'Generic' end
Adam Williams’ Dataset app can leverage your Factories to ease creating sample data. Dataset allows us to create specific sample data for a use case than a blanket amount of fixtures. I use the name_model with Factories to create sample data.
class UsersDataset < Dataset::Base name_model Factory.create(:user, :login => "quentin"), :user_quentin end class CarsDataset < Dataset::Base uses :users name_model Factory.create(:car, :model => "Jazz", :owner_id => users(:user_quentin).id ), :car_jazz end
So when we’re testing our CarsController, we only load the sample data to test for Cars instead of all fixtures.
class CarsControllersTest < ...
dataset :cars
context "A CarsController" do
context "on GET to show" do
setup do
get :show, :id => cars(:car_jazz).id
end
should_render_template :show
...
end
end
end
I also recommend Mocha for mocking and stubbing objects. I know some people use mocks and stubs to force branching conditions in unit tests (i.e. on save fail, object should generate such and such error message). Personally, I prefer to use real data to force those conditions. The exceptions comes when talking to 3rd party systems / APIs. When unit testing, I don’t want my tests trying to talk to another server. I want my tests to be self contained; i.e. I don’t want to run multiple applications just to make my tests pass.
My last note on testing is a bit of advice. I recommend not testing private methods. Searching on Google returns hundreds of different articles on the matter; some for and some against testing private methods. I encourage you to pick a few articles and come to your own decision. At least at this point, I prefer grey box testing. Since you know the underlying structure of the code, you can pass in the right data to pass information through the public methods without resorting to hacking classes to get directly at the private methods.