running Rails unit tests without loading the environment or using a database
Asked Answered
S

3

5

As something of an academic exercise, I thought I'd try to get my unit tests running without loading the Rails env (or hitting the database).

I've seen this done before, and it seems like folks talk about it enough, but I can't find any good/current resources on getting it done.

Does anyone have any good stories or a nice long blog post about how to do this?

Stoicism answered 16/8, 2011 at 14:8 Comment(0)
A
7

An useful link: testing Rails without Rails

Testing without database would involve much mocks & stubs, nothing special to add.

Adalineadall answered 16/8, 2011 at 14:17 Comment(0)
H
4

Check out NullDB. I've had mixed success with it.

The creator & current maintainer are looking to get a new maintainer in so some of its current issues should be ironed out soon.

Houseleek answered 24/4, 2012 at 3:42 Comment(1)
It looks like NullDB has been given a lot of attention sense, and with only one open issue, seems to work well in tandem with CI.Unbelief
H
0

Alternative approach to write application little bit differently.

Extract all important logic you want to test into ruby classes without database dependencies.
Write tests for those classes only - your tests will fly! :)

For example

ProductQuantity = Struct.new(:product_id, :quantity)

class Customer < ActiveRecord
  def create_order(product_quantities)
    product_ids = product_quantities.map(&:product_id)
    products = Product.where(:id => product_ids).pluck(:id, unit_price).to_h

    total = product_quantities.reduce(0) do |sum, p|
      sum += p.quantity * products.fetch(p.product_id, 0)
    end

    Order.create!(:customer_id => id, :total => total)
  end
end

Extract "business logic" out of database dependencies

class Customer < ActiveRecord
  def create_order(product_quantities)
    products = Product.where(:id => product_ids).pluck(:id, unit_price).to_h

    total = CalculateNewOrderTotal.from(products, product_quantities)

    Order.create!(:customer_id => id, :total => total)
  end
end

module CalculateNewOrderTotal
  def self.from(products, product_quantities)
    product_quantities.reduce(0) do |sum, p|
      sum += p.quantity * products.fetch(p.product_id, 0)
    end
  end
end

Now the module CalculateNewOrderTotal can be fully covered with very fast tests which doesn't require mocks or actual database.

You can still write happy path tests with actual database for Customer.create_order method.

Extra benefits

Your business logic is independent of persistence framework.
Your business logic is independent of persistence schema, you can change how to store data without "touching" important business logic code.
No mocks involved
No extra layers of abstractions - you can still use all benefits of the ActiveRecord, for example wrap call of the method with the transaction.
No other frameworks or gems are involved - pure ruby and RSpec or testing framework of your choice :)

Harwood answered 28/10, 2020 at 4:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.