在命名空间模型中使用factory_girl_rails和Rspec

36
我有一个网络服务,向多个不同的客户端提供广告。由于广告的结构因客户而异,我使用命名空间按客户名称对模型和控制器进行区分以区分广告。从高层次上看,它看起来像这样:'app/models/client1/ad.rb'
class Client1::Ad < ActiveRecord::Base
  attr_accessible :title, :description
end

'app/models/client2/ad.rb'

class Client2::Ad < ActiveRecord::Base
  attr_accessible :title, :description, :source
end

实际上,这些模型更加复杂并且具有关联,但这不是重点。
我正在使用rspec-rails 2.4.0和factory_girl_rails 1.0.1编写一些单元测试,我的所有工厂都很好用。然而,我无法为带命名空间的模型定义工厂。我尝试了如下代码:

Factory.define :client1_ad, :class => Client1::Ad do |ad|
  ad.title       "software tester"  
  ad.description "Immediate opening"
end  

Factory.define :client2_ad, :class => Client2::Ad do |ad|
  ad.title       "software tester"  
  ad.description "Immediate opening"
  ad.source      "feed"
end

它没有完成工作。我找了一下,但是我看到的每个示例都使用非命名空间模型。有人有任何想法吗?非常感谢任何输入。

5个回答

49

我这里有一个最小工作示例,也许你可以用它来确定你的问题所在。你在dmarkow的回答中留下的评论让我觉得你在其他地方出现了错误。

app/models/bar/foo.rb

class Bar::Foo < ActiveRecord::Base
end

*db/migrate/20110614204536_foo.rb*

class Foo < ActiveRecord::Migration
  def self.up
    create_table :foos do |t|
      t.string :name
    end
  end

  def self.down
    drop_table :foos
  end
end

spec/factories.rb

Factory.define :foo, :class => Bar::Foo do |f|
  f.name 'Foooo'
end

*spec/models/foo_spec.rb*

require 'spec_helper'

describe Bar::Foo do

  it 'does foo' do
    foo = Factory(:foo)
    foo.name.should == 'Foooo'
  end
end

运行测试:

$ rake db:migrate
$ rake db:test:prepare
$ rspec  spec/models/foo_spec.rb 
.

Finished in 0.00977 seconds
1 example, 0 failures

希望能对您有所帮助。

非常感谢您详细的回答,Jorge。看起来我的问题是我没有运行rake db:test:prepare。已接受,投票支持。 - Simon Bagreev
我很好奇,你的表名应该是bar_foos而不是foos吧? - Mohamad

12

我认为自从这个答案被发布以来,可能FactoryGirl已经有所改变。我做了一些更改让它能够工作。

Factory.define do
  factory :foo, :class => Bar::Foo do |f|
    f.name 'Foooo'
  end
end

8

在当前最新版本的FactoryGirl4.5.0)中,语法如下:

FactoryGirl.define do
  factory :client1_ad, class: Client1::Ad do |f|
    f.title       "software tester"
    f.description "Immediate opening"
  end
end

请注意,client1_ad 可以随意命名,因为我们已经强制识别了它的类名

2

我发现这个问题与 FactoryGirl 有关,经过阅读源代码后,我发现只需要重命名我的工厂,就可以解决我的问题。

当我的模型类被放在模块中时,比如: Admin::User,我应该像这样定义我的工厂:

factory :'admin/user', class: Admin::User do
  #...
end

与其说:

factory :admin_user, class: Admin::User do
  #...
end

也许这个小贴士有一天会对某个人有所帮助。我的问题具体表现为,我尝试在我的RSpec规范中使用build(described_class)从工厂构建实例,并且这对于未命名空间的类完全没有问题,但是对于模块内的类则不行。原因是在查找工厂时,FactoryGirl将使用ActiveSupportunderscore助手来规范化工厂名称。

0
你尝试过传递实际的类,而不是一个包含类名的字符串吗?
Factory.define :client1_ad, :class => Client1::Ad do |ad|

刚试了一下,不行。我得到了“undefined method is' for #<Class:0xbea9024> (NoMethodError)”的错误信息。我还尝试过:Factory.define Client1::Ad do |ad|` - Simon Bagreev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接