I maintain a ruby gem that was without a database migration generator for
far too long. This is a walkthrough on how I TDD‘d a generator to create
its database migration generator.
Our end goal is to create the database migration install action for rails generate double_double:install
What’s a migration generator?
A migration generator is the composition of ActiveRecord migrations within
Rails generators. They are commonly found in Rails engines and plugins.
Rails generators are convenience scripts. Most frequently generators are
used to create or insert boilerplate code into an application.
ActiveRecord migrations are Ruby classes that define a version of the
application’s database. Where each additional database migration only defines
how to incrementally modify the database from the previous version.
Now if we were to combine both of these concepts we arrive at migration
generators. Which are generators that are capable of creating database migrations.
TDD approach
For the purpose of this generator, I am most concerned that the database
migration template is copied into the expected location.
We could further inspect the generated migration for its specific content,
but that’s approaching overkill. As other tests utilize the database, those
tests will certainly fail loudly if there is a problem with our migration.
To assist in our tests we will be using the generator_spec gem. Let’s
add it to our .gemspec. Bundle install.
Our test
The skeleton of our Rspec spec:
Our most significant decision so far was deciding where to temporarily store
the generated files and directories. The tmp directory is an obvious choice.
Let’s continue and add our test case.
Now we have a test to code against. This test will assert:
That the migration exists
That some text in the migration is the classname that we expect
Production code
Fast-forward some TDD and a few cups of coffee…
We wrote a proper database migration template.
And to finish the task we added the actual Rails generator.
You may be asking: What’s the class method next_migration_number?