Testing different database backends on a rails gem - ruby-on-rails

I need orientation implementing the tests of a gem I'd like to build. It's a small gem that adds a new class method to ActiveRecord::Base. This new method will execute some SQL on demmand.
Trouble is, the SQL to be executed depends on the database backend. It's different for SQLite, Postgres and MySQL. The ruby method signature is the same for all database backends - only the SQL changes.
So, how do I make the tests for this?
To clarify: I know how to ask ActiveRecord "what database backend are you on?". What I need is a way to tell RSpec/Minitest/TestUnit "change the database backend to Postgres, and try all tests again. And then MySQL".

Take a look at how DataMapper does this. They pass an environment variable ADAPTER when running the specs, which alters the gems that are installed/loaded by bundler and changes the connection setup in the spec helper. You should be able to do something similar, basically running the full suite once for each possible database backend.
It looks like this when you run the DM core specs:
ADAPTER=mysql bundle install
ADAPTER=mysql bundle exec spec spec
ADAPTER=sqlite bundle install
ADAPTER=sqlite bundle exec rspec spec
I reckon if you want to get the best coverage, this is a good approach. If you want to selectively test different things for different parts of the tests, you'd just have to use conditionals, though (in general) I see conditionals in tests as a bad thing.

Related

Ruby on Rails. Predefined data installation in DB

I am new with Ruby on Rails and have some issues with it. I am writing my application on Rails and i have to install some pre-defined data in my Database to use it in my application. This data is read-only and never change (for example users and roles. There are no use cases to create new users and roles).
So i have to install this data when my application runs first time. I tried to use Migrations to solve this problem, but my manager told me that it is not a right way, cause migrations are usually used to define DB structure changes and not to install any data in DB.
Can you please help me and tell better way to install my pre-defined data using Ruby on Rails?
You'll be able to achieve this using the seeds functionality:
To add initial data after a database is created, Rails has a built-in 'seeds' feature that makes the process quick and easy. This is especially useful when reloading the database frequently in development and test environments. It's easy to get started with this feature: just fill up db/seeds.rb with some Ruby code, and run rake db:seed:
#db/seeds.rb
User.create name: "test", description: "info"
$ rake db:seed
--
If you wanted static data, you'll be able to use a gem such as the config gem -- which gives you the ability to allocate values in config/settings.yml:
This data is then accessible as Settings.company...
You should use seeds. See this rails cast
You could also look at Dibber, that allows you to define your seeds via YML files.
What you are looking to do is seed the database. Rails comes with a db/seeds.rb that you can use to do this. There are also gems such as seed-fu that you could use.
Here is a short tutorial on seeding a database in Rails.

Rails 3 Rake Clone Database for Testing Environment

Is there a rake command in Rails 3 to clone my development database data? I noticed rake db:test:prepare and rake db:test:clone are mentioned throughout various blogs, but running them seems to do nothing. Furthermore, rake -T shows no db:test cases. I've resorted to loading a sql dump for now, but it would be great if I could just clone my existing development data for up-to-date testing.
EDIT --
I desire to test on a database since I am dealing with legacy data that I run through model filters when accessed. Factories won't work for me in this context, since data passed through create is defined as a different schema than that of the legacy data.
rake db:test:prepare is still there even though it doesn't show up in rake -Tdb. I guess the Rails team decided to de-clutter the rake -T output?
I would suggest you not clone your development database but rather rely on factories to give you predictable data you can craft for your exact test cases. Sooner or later, relying on having reliable test data in a database you can access will break your tests. It will also break the tests of anyone else who works on the project. And changes/additions to the data will not propagate to other developers as would your carefully constructed factories.
Look over Machinist, FixJour, FactoryGirl and the lot. They really solve the test data problem well and you check them into version control so the rest of your team has access to them.

Using ActiveRecord models in a gem - how to handle database config

I have several active record models in a rails app and I would like to extract these models into a gem so that I can easily use them in several web apps. The process seems pretty straight forward, except for passing along the configuration for the models. Do I:
Add the configuration yaml file to the gem, thus assuring the databases will always be the same across all apps - seems rigid, esp for testing and dev, though the databases for production will always be consistent.
Use the ActiveRecord hooks to look for a database.yml file in the config directory with the database defined? If so, which hooks should I use?
This is a stupid idea. If you have a better way to handle this, I'm all ears. I'd prefer not to copy and paste.
You should use the host rails app's database config. Your plugin or gem should contain just the database migrations, and a rake task to run them from the host rails app (e.g. myplugin:db:migrate)
If your models need some other configuration file, you should create a rake task (e.g. myplugin:install) to copy it to your host app's config directory. (This task can call the db:migrate task automatically as well.)
Why do you want to embed the database.yml file inside the gem? Each rails application should use it's own database.yml
I would put all the models into a plugin and include that in each rails application that needs the models.

Proper way of testing gems

If a gem has rails dependencies, do you think it is better to write the gem tests in a way they can be run standalone or run them under a rails project?
A gem should be a piece of code which acts stand-alone. Otherwise it is part of the application, so the tests should be created stand-alone as well. In this way others (hypothetically) can perform the tests as well. If the tests depend on your application others cannot test your gem.
Furthermore when you want to test your gem it should not fail because your application is failing. After your gem passed the test, you can test the application knowing that your gem is functioning well (assuming that you tested everything).
Whether the gem is depending on Rails or not is not an issue, since Rails also has been tested (and you can assume it is working properly). So these dependencies do not (/should) influence your gem.
I'd say it depends on the kind of dependencies the gem needs. Eg. if it's just the ActiveRecord it's quite easy to include it into your test suite. In more complex cases you can always mock some of the needed functionality. In a really complex cases, creating a test app is better than nothing (IMO).

Testing rails application with a I18N database backend

I use Rails 2.3 i18n with a database backend plugin :
http://github.com/dylanz/i18n_backend_database
This stores my translations and locales in two DB tables. What would be the best way to get these tables working with my tests? I'm guessing I could write a rake task that would copy the tables from the development DB to the test DB.
Any suggestions?
You could put the data in a seeds.rb file and run that task when loading your test environment. The benefit of this is that you'll also have some way of regaining a basic data structure if you, for some reason, wipe your computer.
One thing you could try is using fixtures for this. Do a google search for db:fixtures:dump or db:fixtures:export_all Rolling own your own implementation should be pretty easy as well.

Resources