使用 Rspec on Rails 测试回调中关联对象的创建
尝试围绕 rspec 和适当的测试进行思考,并且很难正确执行以下操作
假设我们有三个类,例如
Class User
belongs_to :company
has_and_belongs_to_many :roles
end
Class Company
has_many :users
end
Class Role
has_and_belongs_to_many :users
end
在 User 类中,我有 before_create 回调,如果用户是第一个,则分配用户默认的“company_admin”角色与公司关联的用户
def check_for_initial_company_admin_role
if self.company.users.count == 0
self.roles << Role.find_by_name("company_admin")
end
end
如何在模型规范中正确测试用户被分配“company_admin”角色,以防他是第一个与公司关联的用户?
更新 工作解决方案
describe "#check_for_initial_company_admin_role" do
it "sets the first user created to be the administrator" do
Factory(:role)
user = Factory(:user)
user.roles.count.should be > 0
user.roles.should include Role.find_by_name("company_admin")
end
end
Factory.define :user do |f|
f.email { Factory.next(:email) }
f.password "secret"
f.password_confirmation "secret"
f.association :company
end
Factory.define :role do |f|
f.name "company_admin"
end
Factory.define :company do |f|
f.name "foobar"
f.vat_id "1234"
end
Trying to wrap my head around rspec and proper testing and having some hard time to do the following properly
Let's say we have three classes like
Class User
belongs_to :company
has_and_belongs_to_many :roles
end
Class Company
has_many :users
end
Class Role
has_and_belongs_to_many :users
end
In the User class I have before_create callback that assign the user default 'company_admin' role, if the user is first one to be associated with the company
def check_for_initial_company_admin_role
if self.company.users.count == 0
self.roles << Role.find_by_name("company_admin")
end
end
How do I properly test in my model spec that the user gets assigned the 'company_admin' role in case he's the first user associated with the company?
UPDATE
working solution
describe "#check_for_initial_company_admin_role" do
it "sets the first user created to be the administrator" do
Factory(:role)
user = Factory(:user)
user.roles.count.should be > 0
user.roles.should include Role.find_by_name("company_admin")
end
end
Factory.define :user do |f|
f.email { Factory.next(:email) }
f.password "secret"
f.password_confirmation "secret"
f.association :company
end
Factory.define :role do |f|
f.name "company_admin"
end
Factory.define :company do |f|
f.name "foobar"
f.vat_id "1234"
end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会这样处理:
这里的一个可能不正确的假设是您在测试框架中使用 Factory Girl。如果没有,那并没有真正改变这个测试的“内容”......只是您创建公司和用户的第一行。
您还可以选择从公司方面检查用户,但老实说,这感觉像是完全不同的测试 - 测试这些模型之间的关联。
我采取的方法是,由于这实际上是一个模型测试,因此您需要创建和更改真实的模型对象,而不是模拟这些对象。如果这是一个控制器测试,我会模拟模型并积极地存根模型。
我希望这对您有所帮助并解决您的问题。如果没有,请让我知道我的出发点,我会再次通过它:)我只进入 rspec 大约一年,但我发现一旦我开始思考如何测试模型与模型。我已经爱上它了。
I would approach it like this:
An assumption here that may be incorrect is that you are using Factory Girl in your test framework. If not, that doesn't really change the "meat" of this test...just those first lines where you create the company and user.
You could also optionally check the user from the company side of things but honestly that feels like a different test entirely--one testing the association between those models.
The approach I would take is that since this is actually a model test you need to create and alter a real model objects, rather than mocking out those objects. If this were a controller test, I'd mock the models and stub the models aggressively.
I hope this helps and addresses your question. If not, let me know where I'm off base and I'll make another pass at it :) I'm only about a year into rspec but I've found that once I wrapped my head around how to test models vs. controllers I've come to love it.
在不更改现有逻辑的情况下,我将在 user_spec 中测试此逻辑,如下所示:
注意:我将使用 FactoryGirl 之类的内容作为管理角色和公司对象,以使它们可重用。
您使用角色名称来指示行为并不理想。它可能会导致整个应用程序中出现大量分散的逻辑,您可以通过名称查找角色并使用 if/else 或 case 语句检查名称。我建议使用 Rail 的单表继承并将所有管理角色逻辑移至单独的类。它将保持模型的逻辑清晰并使测试变得更加容易。
Without changing your existing logic, I would test this logic in the user_spec like so:
Note: I would be using something like FactoryGirl for the admin role and company objects to make them reusable.
Your use of the role name to indicate behavior is not ideal. It will likely lead to lots of scattered logic throughout your application where you are finding the role by its name and checking the name with if/else or case statements. I would recommend using Rail's single table inheritance and moving all the admin role logic to a separate class. It will keep the model's logic cleaner and make testing much easier.