관련 자식 모델 정보를 포함하는 양식 유효성 검사 (Rspec)

소개



스쿨에서 프리마 앱 개발시, 출품 폼의 밸리데이션 테스트를 담당했습니다.
그 때, 출품 화상의 밸리데이션 테스트로 고생했기 때문에, 복습도 겸해 기사에 남기려고 생각합니다.

이번 사례




  • 상품명이나 상품 설명을 보존하는 테이블(products 테이블)과, 출품 화상을 보존하는 테이블(images 테이블)이 나누어져 존재하고 있다.
  • 연관은 has_many :images와 belongs_to :product의 관계이다.
  • 하나의 폼으로부터, 복수의 테이블에 데이터를 송신해 보존하는 구현을 하고 있다.
  • Product 모델에, validates :images , presence: true를 기재하고 있어 화상이 없으면 상품을 출품할 수 없게 되어 있다.

  • 문제는, 화상이 없으면 출품을 할 수 없기 때문에,
    양식에 이미지가 업로드된 상태를 테스트에서 재현해야 합니다.
    이 경우 어떻게 테스트해야합니까?

    그것에 대해 설명하겠습니다.

    테스트 방법



    먼저 factory_bot을 사용하여 image 정보를 포함하지 않는 Product 모델의 인스턴스를 준비해 보겠습니다.

    spec/factories/products.rb
    FactoryBot.define do
      factory :product do  #画像なしバージョン
        id                {"1"}
        name              {"商品名"}
        detail            {"詳細"}
        category_id       {"686"}
        which_postage     {"1"}
        prefecture        {"1"}
        shipping_date     {"1"}
        price             {"1000"}
        size
        condition
        sending_method
        user
      end
    end
    

    이번 주목하고 싶은 것은 image에 관한 것이므로, 그 이외의 값에 대해서는 신경 쓰지 않아도 괜찮습니다.

    이 상태에서 우선 아래의 테스트를 실행해 보겠습니다.

    spec/models/product_spec.rb
    require 'rails_helper'
    describe Product do
      describe '#create' do
        it "全ての必須項目が入力されている場合出品できる" do
          product = FactoryBot.build(:product)
          expect(product).to be_valid
        end
      end
    end
    

    터미널
    Product
      #create
        全ての必須項目が入力されている場合出品できる (FAILED - 1)
    
    Failures:
    
      1) Product#create 全ての必須項目が入力されている場合出品できる
         Failure/Error: expect(product).to be_valid
           expected #<Product id: 1, name: "商品名", detail: "詳細", shipping_date: 1, price: 1000, which_postage: 1, delivery_status: "出品中", prefecture: 1, created_at: nil, updated_at: nil, brand_id: nil, user_id: 1, size_id: 1, condition_id: 1, sending_method_id: 1, buyer_id: nil, category_id: 686> to be valid, but got errors: 商品画像を入力してください
         # ./spec/models/product_spec.rb:154:in `block (3 levels) in <top (required)>'
    
    Finished in 0.63978 seconds (files took 5.52 seconds to load)
    1 example, 1 failure
    

    당연하지만 "제품 이미지를 입력하십시오"라고 말하고 테스트가 실패합니다.
    product.images의 내용이 비어있는 번역입니다.
    어떻게든 product.images에 이미지 정보를 넣어 주어야합니다.

    이를 위해 image의 factory를 product와는 별도로 준비합니다.

    spec/factories/images.rb
    FactoryBot.define do
    
      factory :image do
        image   {File.open("#{Rails.root}/spec/fixtures/test_image.png")}
        product
      end
    
    end
    

    image가 준비되면 spec/factories/products.rb를 다음과 같이 편집하십시오.

    spec/factories/products.rb
    FactoryBot.define do
      factory :product do  #画像ありバージョン
        id                {"1"}
        name              {"商品名"}
        detail            {"詳細"}
        category_id       {"686"}
        which_postage     {"1"}
        prefecture        {"1"}
        shipping_date     {"1"}
        price             {"1000"}
        size
        condition
        sending_method
        user
        after(:build) do |product|                           #追記
          product.images << build(:image, product: product)  #追記
        end                                                  #追記
      end
    end
    

    세 줄만 추가했습니다.
    after(:build) do |product|
      product.images << build(:image, product: product)
    end
    

    after(:build) do ~ end 부분에서 product의 인스턴스가 작성된 직후에 image의 인스턴스를 작성해, product.images안에 image 인스턴스의 정보를 넣어 줍니다.

    이제 폼에 이미지가 업로드된 상태를 재현할 수 있었습니다!
    다시 테스트를 실행해 봅니다.

    spec/models/product_spec.rb
    require 'rails_helper'
    describe Product do
      describe '#create' do
        it "全ての必須項目が入力されている場合出品できる" do
          product = FactoryBot.build(:product)
          expect(product).to be_valid
        end
      end
    end
    

    터미널
    Product
      #create
        全ての必須項目が入力されている場合出品できる
    
    Finished in 0.54654 seconds (files took 5.16 seconds to load)
    1 example, 0 failures
    

    이번에는 성공입니다! !

    이미지 매수를 변경하려는 경우


    after(:build) do |product|
      product.images << build_list(:image, 10, product: product) #buildをbuild_listへ変更
    end
    

    build 를 build_list 메소드로 하는 것으로, 이미지의 매수도 조작할 수가 있습니다.
    위의 경우 build_list의 두 번째 인수에 10을 전달하기 때문에 이미지가 10 장 업로드 된 상태를 재현합니다.
    경계값 등을 테스트하는 경우는 build_list를 사용하면 좋다고 생각합니다.

    소감



    테스트에 관해서는 검색해도 정보가 적고, 고생했습니다.
    이 기사가 조금이라도 누군가의 도움이되면 기쁩니다.
    첫 투고이므로, 실수 등 있으시면, 지적하실 수 있으면 다행입니다.
    여기까지 읽어 주셔서 감사합니다! !

    참고로 한 기사



    accepts_nested_attributes_for로 작성하는 presence : true가 붙은 아이 모델에 대한 모델의 검증 체크 ~RSpec~
    FactoryBot과 CarrierWave를 사용하여 RSpec에 이미지 파일 업로드 테스트

    좋은 웹페이지 즐겨찾기