factory_bot에서 배열 / 해시를 정의하는 방법은 무엇입니까?


80

Dropbox REST 서비스의 일부 반환 값을 시뮬레이션하는 테스트를 작성하여 중첩 된 해시를 사용하여 배열의 데이터를 반환합니다.

반환 결과가 내부에있는 배열이기 때문에 내 공장을 코딩하는 방법을 알아내는 데 문제가 있습니다. 여기에 무엇이 갈까요?

Factory.define :dropbox_hash do
 ??
end

Dropbox 데이터는 다음과 같습니다.

 ["/home", {"revision"=>48, "rev"=>"30054214dc", "thumb_exists"=>false, "bytes"=>0, "modified"=>"Thu, 29 Dec 2011 01:53:26 +0000", "path"=>"/Home", "is_dir"=>true, "icon"=>"folder_app", "root"=>"app_folder", "size"=>"0 bytes"}] 

그리고 내 RSpec에서 다음과 같은 공장 호출을 원합니다.

Factory.create(:dropbox_hash)

이것을 위해 정말로 공장이 필요합니까? 시뮬레이션 된 응답을 반환하는 메서드를 정의하지 않는 이유는 무엇입니까?
zetetic

그게 내가 한 일입니다. 하지만 공장의 요점은이 물건을 분리하는 것이라고 생각했습니다. 나는 여전히 궁금합니다-Hash와 Array가 클래스 인 것처럼 보이며 올바른 구문을 얻을 수 있다면 작동합니다.
Doug

ActiveRecord 모델 인스턴스를 생성하는 데만 사용했습니다. FactoryGirl은 조명기를 교체하기위한 것입니다. RSpec의 도우미 메서드를 살펴볼 수 있습니다. relishapp.com/rspec/rspec-core/v/2-9/docs/helper-methods
zetetic

답변:


155

나는 똑같은 일을하고, 또한 써드 파티 API의 콘텐츠 해시를 사용하여 작동하는 모델을 테스트하는 데 관심이있었습니다. factory_girl의 몇 가지 내장 기능을 사용하여 이러한 종류의 데이터 구조를 깔끔하게 구성 할 수 있음을 발견했습니다.

다음은 인위적인 예입니다.

  factory :chicken, class:Hash do
    name "Sebastian"
    colors ["white", "orange"]

    favorites {{
      "PETC" => "http://www.petc.org"
    }}

    initialize_with { attributes } 
  end

여기서 주요 트릭은 initialize_with를 선언 할 때 factory_girl이 더 이상 결과 객체에 속성을 할당하려고 시도하지 않는다는 것입니다. 이 경우 db 저장소를 건너 뛰는 것 같습니다. 따라서 복잡한 것을 구성하는 대신 이미 준비된 속성 해시를 콘텐츠로 다시 전달합니다. 짜잔.

실제로 사용되지는 않지만 클래스에 대한 일부 값을 지정할 필요가있는 것 같습니다. 이것은 factory_girl이 팩토리 이름을 기반으로 클래스를 인스턴스화하려고 시도하는 것을 방지하기위한 것입니다. Object 대신 설명 클래스를 사용하기로 선택했지만 그것은 당신에게 달려 있습니다.

다음 해시 팩토리 중 하나를 사용할 때 여전히 필드를 재정의 할 수 있습니다.

chick = FactoryGirl.build(:chicken, name:"Charles")

.. 그러나 중첩 된 콘텐츠가 있고 더 깊은 필드를 재정의하려면 일종의 깊은 병합을 수행하기 위해 초기화 블록의 복잡성을 증가시켜야합니다.

귀하의 경우 일부 혼합 배열 및 해시 데이터를 사용하고 있으며 데이터 구조의 일부간에 Path 속성을 재사용해야하는 것으로 보입니다. 문제 없습니다. 컨텐츠의 구조를 알고 있으므로 결과 배열을 적절하게 구성하는 팩토리를 쉽게 만들 수 있습니다. 방법은 다음과 같습니다.

  factory :dropbox_hash, class:Array do
    path "/home"
    revision 48
    rev "30054214dc"
    thumb_exists false
    bytes 0
    modified { 3.days.ago }
    is_dir true
    icon "folder_app"
    root "app_folder"
    size "0 bytes"

    initialize_with { [ attributes[:path], attributes ] }
  end

  FactoryGirl.build(:dropbox_hash, path:"/Chickens", is_dir:false)

또한 여전히 불필요한 값을 생략 할 수 있습니다. Path와 rev 만 정말로 필요하다고 상상해 봅시다.

  factory :dropbox_hash, class:Array do
    path "/home"
    rev "30054214dc"
    initialize_with { [ attributes[:path], attributes ] }
  end

  FactoryGirl.build(:dropbox_hash, path:"/Chickens", revision:99, modified:Time.now)

이것은 훌륭한 솔루션입니다. 그것은 심지어 공장의 상속과 함께 작동합니다.
David Pelaez 2014 년

이것은 내가 생성 / 빌드하는데 작동하지만 lint는 실패합니다 : FacoryGirl.lint
pixelearth

감사합니다. 에서 Rubocop의 린터 전달하려면 favorites여러 줄 블록 사용 do..end대신을 {{..}}.
scarver2

skip_create대신 'create'를 호출하려면 공장에 추가 할 수 있습니다.build
Sairam

큰. 나는, 사용자 정의 클래스를 초기화 할 수 있습니다 발견 initialize_with클래스 컨텍스트, 즉 내가 가지고있는 경우에 평가하여 initialize_with { new(attributes) }, build :my_factory결과 반환합니다MyClass.new(attributes)
MikDiet

10

나를 위해 작동하고 필요에 따라 속성을 해시에 전달할 수 있습니다.

factory :some_name, class:Hash do
  defaults = {
    foo: "bar",
    baz: "baff"
  }
  initialize_with{ defaults.merge(attributes) }
end

> build :some_name, foo: "foobar" #will give you
> { foo: "foobar", baz: "baff" }

3
이것은 또한 키가 문자열이 될 수 있다는 추가적인 이점을 가질 것입니다.
crftr dec.

여기서 단점은 생성 될 때마다 새 개체가 아닌 단일 개체를 수정한다는 것입니다. 해시의 object_id를 살펴보십시오
Anthony


6

최신 버전의 factory_girl에서이 작업을 수행 할 수 있지만 데이터 구조가 아닌 객체를 빌드하도록 설계 되었기 때문에 어색합니다. 예를 들면 다음과 같습니다.

FactoryGirl.define do
  factory :dropbox_hash, :class => 'Object' do
    ignore do
      url { "/home" }
      revision { 48 }
      rev { "30054214dc" }
      # more attributes
    end
    initialize_with { [url, { "revision" => revision, "rev" => rev, ... }] }
    to_create {}
  end
end

여기서 이상한 것들을 살펴 보자.

  • 모든 팩토리에는 사용되지 않더라도 유효한 빌드 클래스가 필요하므로 Object여기를 통과 하여DropboxHash .
  • ignore블록을 사용하는 모든 속성을 무시하여 나중에 배열에 할당하지 않도록해야합니다.array.revision = 48 .
  • 다음을 사용하여 결과를 조합하는 방법을 알려줄 수 있습니다. initialize_with . 여기서 단점은 전체 속성 목록을 다시 작성해야한다는 것입니다.
  • 나중에 to_create호출을 시도하지 않도록 빈 블록 을 제공해야합니다 array.save!.

0

OpenStruct를 사용했습니다.

factory :factory_hash, class:OpenStruct do
  foo "bar"
  si "flar"
end

편집 : 죄송합니다, 해시로 작동하지 않습니다

마침내 공장 시스템에서 오는 해시를 유지하기 위해 정적 버전을 사용합니다.

factory :factory_hash, class:Hash do
  initialize_with { {
    foo "bar"
    si "flar"
  } }
end

더 나은 것을 찾고

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.