I had a requirement to update a field that went into production with no restrictions to include some restrictions and with that the need to update pre-existing data. I wrote a migration responsible for handling the conversion and I wanted to test all the cases. Here's how I solved the problem, using mocks (Mocha specifically, but rspec's mocks would also work) instead of trying to cram legacy data into the database.

Here's the migration:

# db/migrate/20130113181838_update_public_name_values.rb  
class UpdatePublicNameValues < ActiveRecord::Migration  
  def up
    User.select("id, public_name").each do |user|
      next if user.public_name.nil?
      original_public_name = user.public_name.clone
      user.public_name.gsub!(/[^A-Za-z0-9_]/, '_')
      user.public_name = user.public_name.slice(0,12)
      begin
        if original_public_name != user.public_name
          user.save!
        end
      rescue
        puts "Unable to update #{user.id} (#{original_public_name} => #{user.public_name})"
      end
    end
  end

  def down
    puts "irreversible"
    # a more responsible migration would make this reversible
  end
end

And the spec (no I did not TDD this, I wrote the migration first and the tests second, tsk tsk):

# spec/db/migrate/update_public_name_values_spec.rb  
require "spec_helper"  
require "#{Rails.root}/db/migrate/20130113181838_update_public_name_values"

describe UpdatePublicNameValues do  
  describe "#up" do
    let(:special_char) { User.new(public_name:'Bits & Bytes') }
    let(:long_name) { User.new(public_name:'This is a very long name') }
    let(:normal_name) { User.new(public_name:'SomeUser') }
    let(:error_name) { User.new(public_name:'Causes Error') }
    let(:nil_name) { User.new(public_name:nil) }
    before do
      User.expects(:select).with("id, public_name")
        .returns([special_char, long_name, normal_name, error_name, nil_name])
      special_char.expects(:save!)
      long_name.expects(:save!)
      normal_name.expects(:save!).never
      error_name.expects(:save!).throws(RuntimeError)
      nil_name.expects(:save!).never
    end
    it "performs the appropriate actions" do
      UpdatePublicNameValues.new.up
      special_char.public_name.should == "Bits___Bytes"
      long_name.public_name.should == "This_is_a_ve"
    end
  end
end

I also ran across this post which shows how to verify structural changes during migrations.