作为一项学术练习,我想我会尝试在不加载 Rails 环境(或访问数据库)的情况下运行我的单元测试。
我以前见过这样做,似乎人们谈论它已经足够了,但我找不到任何好的/当前资源来完成它。
有没有人有任何关于如何做到这一点的好故事或一篇不错的长博客文章?
作为一项学术练习,我想我会尝试在不加载 Rails 环境(或访问数据库)的情况下运行我的单元测试。
我以前见过这样做,似乎人们谈论它已经足够了,但我找不到任何好的/当前资源来完成它。
有没有人有任何关于如何做到这一点的好故事或一篇不错的长博客文章?
一个有用的链接:在没有 Rails 的情况下测试 Rails
没有数据库的测试会涉及很多模拟和存根,没有什么特别要添加的。
查看NullDB。我的成功参差不齐。
创建者和当前维护者正在寻找新的维护者,因此应该尽快解决其当前的一些问题。
编写应用程序的替代方法略有不同。
将您要测试的所有重要逻辑提取到没有数据库依赖关系的 ruby 类中。
只为这些类编写测试——你的测试会飞起来!:)
例如
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
从数据库依赖中提取“业务逻辑”
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
现在,该模块CalculateNewOrderTotal
可以完全覆盖非常快速的测试,不需要模拟或实际数据库。
您仍然可以使用实际数据库为Customer.create_order
方法编写快乐路径测试。
额外福利
您的业务逻辑独立于持久性框架。
您的业务逻辑独立于持久性模式,您可以更改存储数据的方式,而无需“接触”重要的业务逻辑代码。
不涉及模拟
没有额外的抽象层 - 您仍然可以使用 ActiveRecord 的所有好处,例如将方法的调用与事务一起包装。
不涉及其他框架或 gem - 纯 ruby 和 RSpec 或您选择的测试框架:)