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 :)
精彩评论