开发者

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

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?


An useful link: testing Rails without Rails

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


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.


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 :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜