Rails测试has_many关联失败

时间:2011-09-25 05:27:05

标签: ruby-on-rails ruby testing associations

我有2个型号。一个User和一个Task。以下是他们的代码:

class User < ActiveRecord::Base
  has_many :tasks
  has_many :assigned_tasks, :class_name => 'Task', :foreign_key => 'assigned_user_id'
end

class Task < ActiveRecord::Base
  belongs_to :user
  belongs_to :assigned_user, :class_name => 'User', :foreign_key => 'assigned_user_id'
end

架构非常明显,但为了保持一致性,它的外观如下:

ActiveRecord::Schema.define(:version => 20110925050945) do
  create_table "tasks", :force => true do |t|
    t.string   "name"
    t.integer  "user_id"
    t.integer  "assigned_user_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "users", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end

我为assigned_tasks关系添加了一个测试用例。它看起来像这样:

class UserTest < ActiveSupport::TestCase
  test "assigned tasks" do
    u1 = User.create(:name => 'john')
    u2 = User.create(:name => 'dave')

    assert_empty u2.assigned_tasks # LOOK AT ME

    task = u1.tasks.create(:name => 'some task', :assigned_user_id => u2.id)

    assert_equal 1, u2.assigned_tasks.size
  end
end

现在,这个测试用例失败了。它在最后一个断言中失败了。如果我删除了之前的断言(标记为“LOOK AT ME”),则该测试通过正常。如果我将此行更改为assert u2.assigned_tasks,它也会正常传递。这意味着只有当empty?u2.assigned_tasks调用时,它才会出现中断。在断言通过的地方,下面的一个失败了。这是失败:

UserTest:
     FAIL assigned tasks (0.12s) 
          <1> expected but was
<0>.
          test/unit/user_test.rb:12:in `block in <class:UserTest>'

因此,在原始empty?数组上调用u2.assigned_tasks后,该任务实际上并未与其指定的用户相关/关联。然而,这似乎在控制台中工作正常。

道歉,如果我完全忽略了这里简单的事情,但我真的无法理解这一点。正确方向的任何一点都会非常有帮助。感谢

PS:Rails 3.1 with vanilla application

1 个答案:

答案 0 :(得分:2)

您需要重新加载assigned_tasksu2

# This line causes assigned_tasks to be loaded and cached on u2.  Not the calling
# of empty?, but rather the loading of the association.
assert_empty u2.assigned_tasks

# but then you actually make the task here
task = u1.tasks.create(:name => 'some task', :assigned_user_id => u2.id)

# so when this assertion happens, u2 already has an empty set of tasks cached, 
# and fails
assert_equal 1, u2.assigned_tasks.size

# however either of these should pass
assert_equal 1, u2.assigned_tasks(true).size
assert_equal 1, u2.reload.assigned_tasks.size

inverse_of选项用于改善内存中的关联行为,也可能解决您的问题(无需重新加载)。阅读here。它看起来像这样(但是我不肯定它会在这种情况下起作用):

# on User
has_many :assigned_tasks, ..., :inverse_of => :assigned_user

# on Task
belongs_to :assigned_user, ..., :inverse_of => :assigned_tasks

# in your test you might have to change the task creation to:
u1.tasks.create(:name => 'some task', :assigned_user => u2)