rspec에서 NameError: wrong constant name 오류 해결


polymorphic association에서 factory_gir을 사용하여 rspec 상에서 unit test를 작성하는데 어려움이 있습니다.

실험을 위해서 아주 기본 예제로 하였는데

기본예제에서도 왜인지 파악되지 않는 오류가 있어서 이렇게 도움을 청합니다...

# db/schema.rb

ActiveRecord::Schema.define(version: 20160412134106) do

  create_table "cars", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "pictures", force: :cascade do |t|
    t.integer  "imageable_id"
    t.string   "imageable_type"
    t.string   "name"
    t.datetime "created_at",     null: false
    t.datetime "updated_at",     null: false
  end

end

schema가 위와 같이 되어있고,

아주 기본적인 polymorphic association을 하였습니다.

# app/models/picture.rb

class Picture < ActiveRecord::Base
  belongs_to :imageable, polymorphic: true
end
# app/models/car.rb

class Car < ActiveRecord::Base
  has_many :pictures, as: :imageable
end

위와 같이 rails polymorphic 예제와 동일하게 구성해보았습니다.

그리고 factory girl과 rspec를 이용해서 test를 아래와 같이 작성하였는데요...

# spec/factories/pictures.rb

FactoryGirl.define do
  factory :car_picture do
    association :imageable, factory: :car
  end
end
# spec/factories/cars.rb

FactoryGirl.define do
  factory :car do
    name "MyString"
  end
end
# spec/models/car_spec.rb

require 'rails_helper'

RSpec.describe Car, type: :model do
  let(:car_picture) { build(:car_pictur) }
  it { expect(car_picture).to validate_uniqueness_of(:imageable_type).scoped_to(:imageable_id) }
end

rspec 명령을 수행하면

$ bundle exec rspec -b
F

Failures:

  1) Car
     Failure/Error: let(:car_picture) { build(:car_picture) }

     NameError:
       uninitialized constant CarPicture

     ...

Finished in 0.00241 seconds (files took 1.4 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/car_spec.rb:5 # Car

$

위와 같이 uninitialized constant CarPicture라는 오류가 나는데 왜 나는지 모르겠네요...

추가 질문

댓글에서 언급한 오류를 질문용 프로젝트에도 재현하였습니다.

# app/models/picture.rb

class Picture < ActiveRecord::Base
  belongs_to :imageable, polymorphic: true

  validates :imageable_type, uniqueness: { scope: :imageable_id } # 추가된 행!!!!!!!
  validates :imageable, presence: true # 추가된 행!!!!!!!
end

다른 코드들은 답변으로 제시해주신 factory명과 해당 클래스명이 다를때 사용하는 class: Picture를 추가하였고, 나머지는 전부 같고 위 picture.rb에서 마지막쯤에 validates :imageable, presence: true # 추가된 행!!!!!!!을 추가하고 test를 돌리니

아래와 같은 오류가 발생합니다.(댓글에서도 언급한..)

$ bundle exec rspec
F

Failures:

  1) Car should validate that :imageable_type is case-sensitively unique within the scope of :imageable_id
     Failure/Error: it { expect(car_picture).to validate_uniqueness_of(:imageable_type).scoped_to(:imageable_id) }

     NameError:
       wrong constant name cAR
     # ./spec/models/car_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.03813 seconds (files took 1.39 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/car_spec.rb:5 # Car should validate that :imageable_type is case-sensitively unique within the scope of :imageable_id

$

spec/factories/pictures.rb에서

FactoryGirl.define do
  factory :car_picture, class: Picture do
    association :imageable, factory: :user
  end
end

car대신 user로 바꾸니

$ bundle exec rspec
F

Failures:

  1) Car should validate that :imageable_type is case-sensitively unique within the scope of :imageable_id
     Failure/Error: it { expect(car_picture).to validate_uniqueness_of(:imageable_type).scoped_to(:imageable_id) }

     NameError:
       wrong constant name uSER
     # ./spec/models/car_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.04852 seconds (files took 2.14 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/car_spec.rb:5 # Car should validate that :imageable_type is case-sensitively unique within the scope of :imageable_id

$

위와 같이 wrong constant name uSER과 같이 모델이름에서 첫문자만 소문자이고 나머지는 전부 대문자로 되는현상이 보였고, 모델이름이 UserFriend라면 uSERfRIEND 로 오류가 나느 현상이 보여졌습니다...

뭐가 문제일까요?


조회수 235


2 답변


Problem:

# spec/factories/pictures.rb

FactoryGirl.define do
  factory :car_picture do
    association :imageable, factory: :car
  end
end

spec/factories/pictures.rb에 정의하신 factory :car_picture 이 부분이 문제가 되는 부분인데요.

Solution:

Factory명이 해당 클래스명과 다를시엔,

FactoryGirl.define do
  factory :car_picture, class: Picture
    ...
  end
end

이렇게 정의 해주셔야합니다.

만약, 상속 개념을 사용하신다면

FactoryGirl.define do
  factory :picture do
    ... # 공통적으로 사용할 attributes은 여기로
  end

  factory :car_picture, parent: :picture do
    association :imageable, factory: :car
  end
end

이런식으로 사용하시면 됩니다.


  • 답변감사합니다. 예제코드에서는 말씀해주신대로 하니까 잘 됐는데... 실제 프로젝트 코드에서는 또 요상하게 오류가 나네요... `wrong constant name uSER` 이런식...?    root   2016.4.13 02:02     
  • 저 user이 `association :imageable, factory: :car` 이부분에서 car대신 :user을 넣었더니 저렇게 되고 저 자리에 또 다른 (실제 있는) factory를 넣으니까 같은 형태로 첫문자만 소문자 뒷 문자는 전부 대문자로 오류가 나네요... car을 넣으면 cAR, card를 넣으면 cARD... 이건 뭘까요...?    root   2016.4.13 02:05     
  • stacktrace는 거의 비슷하네요...? 똑같나... 아무튼 얼핏 보기에 똑같습니다...    root   2016.4.13 02:06     
  • 새로 발생하는 문제에 대해선 질문을 새로 작성해서 작성하신 코드와 함께 올려주세요. 코드 없이 설명만으론 문제점을 찾기가 힘드네요.    김현일 (Kevin Kim)   2016.4.13 02:52     
  • @김현일님 계속적인 답변 감사드립니다. 윗 댓글에서 언급한 새로 발생한 문제에 대해서 본문에 추가하였습니다. 한번서 살펴봐 주셔요... 감사합니다!    root   2016.4.13 13:49     

추가 질문에 대한 답변

Problem:

NameError:
  wrong constant name cAR

shoulda-matchersvalidate_uniqueness_of 메소드는 uniqueness를 테스트하기 위해서 내부적으로 두개의 객체를 생성합니다. 한개는 uniqueness로 정의된 attribute과 같은 값, 또 하나는 uniqueness로 정의된 attribute과 다른 값을 가진 객체 두개를 생성합니다.

지금 uniqueness를 테스트하려는 attribute이, polymorphic association의 :imageable_type인데,

uniqueness를 테스트하기 위해 두개의 객체를 생성하는 과정에서

"Car" 클래스명을 가진 객체를 하나 생성하고, "cAR" 클래스명을 가진 객체를 하나 생성하려고 하는데, cAR라는 클래스가 존재하지 않기 때문에 에러가 발생하는 것입니다.

  • 여기서 "cAR" 클래스명이 어떻게 나왔냐면, shoulda-matchers 내부적으로 다른 값을 생성할 때, value.swapcase와, value.next 이 두가지 메소드를 사용하여 다른 값을 생성합니다. 여기서 "Car".swapcase의 결과 값이 "cAR"이 됩니다. (참고: "User".swapcase의 결과 값은 "uSER").

Solution:

해결 방법은,

class Picture < ActiveRecord::Base
  ...
  validates :imageable_id, uniqueness: { scope: :imageable_type }
end
RSpec.describe Car, type: :model do
  ...
  it { expect(car_picture).to validate_uniqueness_of(:imageable_id).scoped_to(:imageable_type) }
end

테스트하려는 uniqueness의 attribute를 imageable_id으로 하고, imageable_type을 scope으로 정의하면 원하시는 테스트를 하실 수 있을거같습니다.


로그인이 필요한 기능입니다.

Hashcode는 개발자들을 위한 무료 QnA사이트 입니다. 작성한 답변에 다른 개발자들이 댓글을 작성하거나 좋아요/싫어요를 할 수 있기 때문에 계정을 필요로 합니다.
► 로그인
► 계정만들기
Close