The Blog

Posts from April 2010

Apr 28

It's My Gem In A Box

By David Czarnecki

Hey developers, I got something real important to give you. So just sit down, and listen.

We recently started a number of projects, each of which will require the use of a common library. So, here’s how it went down:

* Create the common library as a gem using the jeweler tool.

* Install Gem in a Box to allow the gem to be downloaded internally by our developers using gem install.

* Upload the common library gem.

BLAMMO! Now every developer can pull my gem ;)

But seriously, “Gem in a Box” is awesome and a great way to share gems internally at your office.

Apr 19

Packaging For Pleasure

By David Czarnecki

Let me be more explicit and say I’m going to be talking about Rails application packaging. Sorry, I needed a good post title for the lulz and the page views.

There are a few rake tasks that I’ve been using more and more now that all of our applications are running in a shared, virtual enviroment. They are:

  • rake -T     # -T, –tasks [PATTERN]            Display the tasks (matching optional PATTERN) with descriptions, then exit.

Everyone should know and use this task at least once in their Rails-development life.

  • rake rails:freeze:gems   # Lock this application to the current gems (by unpacking them into vendor/rails)
  • rake gems:unpack   # Unpacks all required gems into vendor/gems.
  • rake gems:unpack:dependencies   # Unpacks all required gems and their dependencies into vendor/gems.

So, once I’ve created my project with “rails [project name]”, then next thing I do is “rake rails:freeze:gems” to freeze the Rails gems. I’ll enumerate the application’s dependencies in the environment.rb file and then run “rake gems:unpack” to make sure those dependencies exist with the application. Example:

config.gem 'will_paginate', :version => '2.3.11', :source => 'http://gemcutter.org'
config.gem 'factory_girl', :version => '1.2.4', :source => 'http://gemcutter.org'
config.gem 'fakeweb', :version => '1.2.8', :source => 'http://gemcutter.org'

Why do I like this approach? In a shared environment, it means we don’t have to have our systems folks install any dependencies for our application to run making the application self-contained. This is mostly fine for gems that don’t have an explicit native component. Also, in being explicit about versions of the gems that an application is using, we do not run the risk of chasing a moving target. Again, in a shared environment, if someone updates a gem on the system, it’s probably not an issue until the one time it is and you’re being called at 3 AM that the application is down because of a gem incompatibility change.

That’s it. Any other packaging dos and don’t?

Apr 9

As It Turns Out, Faking It Is OK

By David Czarnecki

This post is totally SFW. That’s all your going to get in this teaser.

when_harry_met_sally

I just inherited an application and was adding some tests and noticed that one of the tests was randomly failing. As I dug in more, this particular controller test, in executing the controller’s index method, was actually calling out on the intertubes to request some data. For an integration test that’s probably OK, but my view is that unit and functional tests should be self-contained.

Enter Fakeweb.

“FakeWeb is a helper for faking web requests in Ruby. It works at a global level, without modifying code or writing extensive stubs.”

3 lines of code later and I have a self-contained functional test that works with real data.

def setup
  FakeWeb.allow_net_connect = false
end

def teardown
  FakeWeb.allow_net_connect = true
end

test "should get index" do
  FakeWeb.register_uri(:get, 'http://my.real.url.on.the.internets.com', :body => File.join(File.dirname(__FILE__), '../fakeweb', 'some-file.xml'), :content_type => "text/xml")

  get :index
  assert_response :success

 ...

All I needed to do was simply register the URI that was being referenced in my test, provide a valid (or invalid depending on the test) response, and my test will never try to access the real internet.

Apr 7

The Importance of Having a (Fast) Test Suite

By David Czarnecki

Speed is the name of the game. Or is it?

I was adding another project to our Continuous Integration (CI) server that runs the test suite for a project after code is checked in and started noticing the time it takes to build certain projects. A few interesting statistics for you to noodle on.

Average build time: ~32 seconds

Max build time: 1 hour and 48 minutes

There are approximately 18 projects that get built through CI and many other projects that have not been setup for CI.

What does this tell us? Testing is not an impediment to development because it takes too long to run tests. As most test suites run in less than a minute, not running the test suite is not an option for our developers. And if you don’t, CI sends an e-mail to the team letting everyone know you broke the build. And since our post-commit hooks for SVN and git notify our Campfire room each time code is committed, chances are you’re going to get an earful in Campfire telling you to fix the build because your last commit broke the build.

chet_weird_science

I’m glad nearly all of our projects have test suites that run quickly, but I also have a practical view on test suites. Above all, if nothing else, I want a test suite to exist. I want it to be there so that when I’m adding code to the repository, the test suite is looking at me asking for more.

More tests please!

About that project that takes 1 hour and 48 minutes to build? Right. Guitar Hero. It’s a BIG project. It’s over 3 years old. There is a LOT of code. We test A LOT of systems, e.g. accounts, clans, tournaments, leaderboards, game configurations, game integration processing, etc. I’m OK with it taking that long to run the test suite. We have development practices that we follow for running sub-sections of the test suite when we touch the application to test our new code.

To summarize:

  • Ensure your projects have a test suite
  • Run a Continuous Integration (CI) server for your projects for when developers forget to run the test suite before committing code
  • Ensure your projects have a test suite
  • Ensure your projects have a test suite
  • Ensure your projects have a test suite
  • Make sure developers know how to run part of the test suite for long-running test suites
  • Ensure your projects have a test suite