Should Matcher에서 AttributeDoesNotExistError는 어떤 에러인가요...?

조회수 1959회

rspec과 factory-girl, shoulda-matcher을 이용해서 model spec를 작성하고있는데요.

shoulda-matcher에서 제공해주는 validate_presence_of를 이용해서 필드에 empty나 false가 들어 갈 수 없다는 spec를 작성해보고있는데요.

AttributeDoesNotExistError가 납니다...

아마 제가 shoulda-matcher 설정이나 설치를 잘못한것같은데, 어느부분을 봐야할지 몰라서요...

Gemfile

source 'https://rubygems.org'
ruby '2.3.0'


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.6'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'

# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
gem 'pry'
gem 'pg', '~> 0.18.4'
gem 'figaro', '~> 1.1.1'
gem 'pry-rails'

# Use Unicorn as the app server
# gem 'unicorn'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

group :test do
  gem 'database_cleaner', '~> 1.5.1'
  gem 'shoulda-matchers', '~> 3.1.1'
end

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'
  gem 'rspec-rails', '~> 3.4.2'
  gem 'guard', '~> 2.13.0'
  gem 'guard-rspec', '~> 4.6.5'
  gem 'factory_girl_rails', '~> 4.7.0'
  gem 'faker', '~> 1.6.3'
end

group :development do
  gem 'web-console', '~> 2.0'

  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'annotate'
end

spec/spec_helper.rb

require 'database_cleaner'

RSpec.configure do |config|
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
    expectations.syntax = :expect
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end
end

spec/rails_helper.rb

ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'shoulda/matchers'

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  config.use_transactional_fixtures = true

  config.infer_spec_type_from_file_location!

  config.filter_rails_from_backtrace!
end

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

spec/factories/content.rb

# == Schema Information
#
# Table name: contents
#
#  id         :integer          not null, primary key
#  txt        :text
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

FactoryGirl.define do
  factory :content do
    txt { Faker::Lorem.paragraph }
  end
end

app/model/content.rb

# == Schema Information
#
# Table name: contents
#
#  id         :integer          not null, primary key
#  txt        :text
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

class Content < ActiveRecord::Base
  validates :txt, presence: true
end

Content 모델은 정상적으로 생성되어있습니다.

$ rails c
Running via Spring preloader in process 8237
Loading development environment (Rails 4.2.6)
[1] pry(main)> Content.create(txt: Faker::Lorem.paragraph)
   (0.2ms)  BEGIN
  SQL (2.1ms)  INSERT INTO "contents" ("txt", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["txt", "Amet temporibus nobis deserunt adipisci. Eligendi eveniet quo cumque voluptas ut quibusdam autem. Recusandae tempore consectetur qui veniam est hic voluptatem. Aliquam maxime et accusantium nostrum ad. Earum molestiae amet modi cupiditate id ut et."], ["created_at", "2016-04-11 02:08:09.637109"], ["updated_at", "2016-04-11 02:08:09.637109"]]
   (6.3ms)  COMMIT
=> #<Content:0x007fb828712d60
 id: 1,
 txt:
  "Amet temporibus nobis deserunt adipisci. Eligendi eveniet quo cumque voluptas ut quibusdam autem. Recusandae tempore consectetur qui veniam est hic voluptatem. Aliquam maxime et accusantium nostrum ad. Earum molestiae amet modi cupiditate id ut et.",
 created_at: Mon, 11 Apr 2016 11:08:09 KST +09:00,
 updated_at: Mon, 11 Apr 2016 11:08:09 KST +09:00>
[2] pry(main)> Content.last
  Content Load (0.4ms)  SELECT  "contents".* FROM "contents"  ORDER BY "contents"."id" DESC LIMIT 1
=> #<Content:0x007fb822044700
 id: 1,
 txt:
  "Amet temporibus nobis deserunt adipisci. Eligendi eveniet quo cumque voluptas ut quibusdam autem. Recusandae tempore consectetur qui veniam est hic voluptatem. Aliquam maxime et accusantium nostrum ad. Earum molestiae amet modi cupiditate id ut et.",
 created_at: Mon, 11 Apr 2016 11:08:09 KST +09:00,
 updated_at: Mon, 11 Apr 2016 11:08:09 KST +09:00>
[3] pry(main)>

spec/models/content_spec.rb

# == Schema Information
#
# Table name: contents
#
#  id         :integer          not null, primary key
#  txt        :text
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

require 'rails_helper'

describe Content do
  let(:content) { create(:content) }
  it 'is valid' do
    expect(build(:content)).to be_valid
  end

  it { expect(:content).to validate_length_of(:txt).is_at_least(100) }
end

rspec 실행

$ bundle exec rspec
.F

Failures:

  1) Content should validate that :txt cannot be empty/falsy
     Failure/Error: it { expect(:content).to validate_presence_of :txt }

     Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeDoesNotExistError:
       The matcher attempted to set :txt on the Symbol to nil, but that
       attribute does not exist.
     # ./spec/models/content_spec.rb:19:in `block (2 levels) in <top (required)>'

Finished in 0.29974 seconds (files took 1.49 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/models/content_spec.rb:19 # Content should validate that :txt cannot be empty/falsy

$

아무리 봐도 뭐가 문제인지 모르겠네요... ㅠㅠ

  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • Problem

    it { expect(:content).to validate_length_of(:txt).is_at_least(100) }
    

    expect:content 심볼을 넘겨서 그런거 같습니다.

    Solution

    it { expect(content).to validate_length_of(:txt).is_at_least(100) }
    

    위와 같이 let으로 정의하신 content 변수를 넣으시거나, 또는

    it { should validate_length_of(:txt).is_at_least(100) }
    

    or

    it { is_expected.to validate_length_of(:txt).is_at_least(100) }
    

    이렇게 shoulda-matchers 에서 제공하는 shorthand method를 사용하시면 될 거 같습니다.

    • (•́ ✖ •̀)
      알 수 없는 사용자
    • (•́ ✖ •̀)
      알 수 없는 사용자
    • 헉 감사합니다...! 바로 해결되었네요.. 이런걸 발견 못하고.. ㅠㅠ 알 수 없는 사용자 2016.4.11 12:28

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)