英文:
RSpec - failing test unless local variable is called from pry point
问题
我有以下的代码:
## teams_controller.rb
def destroy
ActiveRecord::Base.transaction do
team_admins = team.team_admins
binding.pry
team.destroy!
team_admins.each(&:update_team_admin_role_if_needed!)
end
respond_with_200(team, serializer: V1::User::Management::TeamSerializer)
end
以及相应的规范以确保上述代码的最后一行被执行:
## teams_controller_spec.rb
it 'demotes team admins to employees when needed' do
team_admin_account = create(:account)
admin_team_membership = create(:team_membership, team: @team, admin: true, account: team_admin_account)
team_admin_account.update!(role: Role.team_admin)
expect { process_destroy(team_id: @team.slug) }
.to change { team_admin_account.reload.role }
.from(Role.team_admin)
.to(Role.employee)
end
当我在我的应用程序中使用上述代码时,它按预期工作,但是规范失败,因为帐户似乎从未更新其角色:
expected `team_admin_account.reload.role` to have changed from #<Role id: 4, add_to_first_user_in_organisation: false, title: "Team admin", created_at: "2020-01-03 09:04:28", updated_at: "2020-01-03 09:04:28", management: false, cms_access: false> to #<Role id: 3, add_to_first_user_in_organisation: false, title: "Employee", created_at: "2020-01-03 09:04:28", updated_at: "2020-01-03 09:04:28", management: false, cms_access: false>, but did not change
当我在我的规范中触发 pry 点并立即退出时,规范失败。同样,当没有 pry 点时也会失败。
但是,当我在 pry 点中输入 team_admins
(这会返回我在规范中创建的一个 team_admin),然后退出规范时,规范通过了,并且帐户的角色得到了更新。
有人知道为什么手动调用 team_admins
会使我的规范通过吗?
谢谢提前回答
编辑:
对代码的以下更改也使规范通过:
def destroy
ActiveRecord::Base.transaction do
team_admins = team.team_admins
puts team_admins ## <---- 添加这一行使规范通过
team.destroy!
team_admins.each(&:update_team_admin_role_if_needed!)
end
respond_with_200(team, serializer: V1::User::Management::TeamSerializer)
end
英文:
I have the following code:
## teams_controller.rb
def destroy
ActiveRecord::Base.transaction do
team_admins = team.team_admins
binding.pry
team.destroy!
team_admins.each(&:update_team_admin_role_if_needed!)
end
respond_with_200(team, serializer: V1::User::Management::TeamSerializer)
end
And the corresponding spec to ensure the last line of the above code fires:
## teams_controller_spec.rb
it 'demotes team admins to employees when needed' do
team_admin_account = create(:account)
admin_team_membership = create(:team_membership, team: @team, admin: true, account: team_admin_account)
team_admin_account.update!(role: Role.team_admin)
expect { process_destroy(team_id: @team.slug) }
.to change { team_admin_account.reload.role }
.from(Role.team_admin)
.to(Role.employee)
end
When I use the above code in my application it works as expected, however the spec fails as the account apparently never has their role updated:
expected `team_admin_account.reload.role` to have changed from #<Role id: 4, add_to_first_user_in_organisation: false, title: "Team admin", created_at: "2020-01-03 09:04:28", updated_at: "2020-01-03 09:04:28", management: false, cms_access: false> to #<Role id: 3, add_to_first_user_in_organisation: false, title: "Employee", created_at: "2020-01-03 09:04:28", updated_at: "2020-01-03 09:04:28", management: false, cms_access: false>, but did not change
When I hit the pry point in my spec and quit out straight away, the spec fails. Likewise when there is no pry point.
However when I enter team_admins
at the pry point (which returns the one team_admin I create in my spec) and then quit out of the spec, the spec passes and the account has their role updated.
Anyone have any idea why manually calling team_admins
makes my spec pass?
Thanks in advance
EDIT:
The following change to the code also makes the spec pass:
def destroy
ActiveRecord::Base.transaction do
team_admins = team.team_admins
puts team_admins ## <---- Adding this makes the spec pass
team.destroy!
team_admins.each(&:update_team_admin_role_if_needed!)
end
respond_with_200(team, serializer: V1::User::Management::TeamSerializer)
end
答案1
得分: 1
team_admins
是来自 team
的 AssociationRelation。直到被引用,比如使用 each
或 puts
,它才会执行查询。
在调用 team_admins.each
之前调用了 team.destroy!
。所以当 team_admins.each
执行时,已经没有 team
了,因此也没有了 team_admins
。你可以通过观察 logs/test.log
并查看查询以及它们何时执行来验证这一点。
恭喜,你发现了一个 bug。在销毁 team
之前执行 team_admins.each
。
英文:
team_admins
is an AssociationRelation from team
. This does not execute a query until referenced, such as with each
or puts
.
team.destroy!
is called before team_admins.each
is called. So when team_admins.each
executes there is no more team
and thus no team_admins
. You should be able to verify this by watching logs/test.log
and looking at the queries and when they are executed.
Congratulations, you've found a bug. Execute team_admins.each
before destroying team
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论