如何测试before_destroy回调最小测试



昨天我问了一个关于如何使用Minitest单元测试私有方法的问题

我被告知永远不要测试私有方法。

所以我将逻辑从控制器中取出并放入模型中现在看起来是这样的

class Store < ApplicationRecord
attr_accessor :selected_store_id

before_destroy :move_employees_to_selected_store

scope :by_name, -> { order(name: :asc) }
belongs_to :organization
has_many :employments
validates_presence_of :name
def move_employees_to_selected_store
return unless selected_store_id.present?
store = organization.store.find(selected_store_id)
employments.update_all(store_id: store.id)
end
end

这是可行的!(在视图中更新selected_store_id)

但是我遇到了一个问题,因为我不知道如何测试这个方法,因为我不能通过selected_store_id

我正要尝试下面的断言,但该断言将不成立!

def test_employments_are_moved_to_selected_store_when_store_is_removed
u = UserFactory.create
o = OrganizationFactory.create
s1 = o.store.create(name: "Test")
s2 = o.store.create(name: "Test 2")
s1.employments.create(user: u)
s1.destroy
assert_equal s2.employments.count, 1
end

我如何重构我的测试或回调来传递存储id?

你的控制器知道选择一个选定的商店。并且知道它需要在销毁之前执行此操作。

让控制器实际转移员工,隐藏的逻辑更少,更容易测试。

class Store < ApplicationRecord
scope :by_name, -> { order(name: :asc) }
belongs_to :organization
has_many :employments
validates_presence_of :name
def transfer_employees(new_store)
employments.update_all(store_id: new_store.id)
end
end
class StoreController
def destroy # before (I'm guessing)
@store = Store.find(params[:store_id])
@store.selected_store_id = params[:selected_store_id]
@store.destroy
end
def destroy # after
@store = Store.find(params[:store_id])
@new_store = Store.find(params[:selected_store_id])
@store.transfer_employees(@new_store)
@store.destroy
end
end
class StoreTest
def test_employments_are_transferred
u = UserFactory.create
o = OrganizationFactory.create
s1 = o.stores.create(name: "Test")
s2 = o.stores.create(name: "Test 2")
s1.employments.create(user: u)
s1.transfer_employees(s2)
assert_equal s2.employments.count, 1
end
end

如果您注意到store destroy开始获取邮件列表和其他逻辑,请将其移动到服务/事务对象。

class StoreController
def destroy
@store = Store.find(params[:store_id])
@new_store = Store.find(params[:selected_store_id])
DestroyStore.new.destroy_store(@store, @new_store)
end
end
class DestroyStoreService
def destroy_store(store1, store2)
store1.transfer_employees(store2)
store1.destroy
end
end

不是最优的,但是您可以将服务层移到对象中,但是我倾向于在可能的情况下将业务逻辑与数据层分开。

class Store
def destroy_and_transfter(new_store)
transfer_employees(new_store)
destroy
end
end

好运

最新更新