Làm thế nào để xác định một mảng / băm trong factory_bot?


80

Tôi đang cố gắng viết một bài kiểm tra mô phỏng một số giá trị trả về từ dịch vụ REST của Dropbox để trả lại cho tôi dữ liệu trong Mảng, với hàm băm lồng nhau.

Tôi đang gặp khó khăn khi tìm cách viết mã Factory của mình vì kết quả trả về là một mảng có dấu bên trong. Điều gì sẽ xảy ra ở đây?

Factory.define :dropbox_hash do
 ??
end

Dữ liệu Dropbox trông giống như sau:

 ["/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"}] 

Và tôi muốn một cuộc gọi xuất xưởng như thế này trong RSpec của mình:

Factory.create(:dropbox_hash)

Bạn có thực sự cần một nhà máy cho việc này? Tại sao không chỉ định nghĩa một phương thức trả về phản hồi mô phỏng?
zetetic

Đó là những gì tôi đã kết thúc. Nhưng tôi nghĩ quan điểm của Nhà máy là cô lập thứ này. Tôi vẫn tò mò - có vẻ như Hash và Array là các lớp và điều này sẽ hoạt động nếu tôi chỉ cần có được cú pháp phù hợp.
Doug

Tôi chỉ sử dụng chúng để tạo các phiên bản mô hình ActiveRecord. FactoryGirl được dùng để thay thế đồ đạc. Bạn có thể có một cái nhìn tại các phương pháp helper RSpec của: relishapp.com/rspec/rspec-core/v/2-9/docs/helper-methods
zetetic

Câu trả lời:


154

Tôi muốn làm điều tương tự, cũng để kiểm tra một mô hình của tôi hoạt động bằng cách sử dụng hàm băm từ API của bên thứ ba. Tôi thấy rằng bằng cách sử dụng một vài tính năng tích hợp của factory_girl, tôi đã có thể xây dựng rõ ràng các loại cấu trúc dữ liệu này.

Đây là một ví dụ giả định:

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

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

    initialize_with { attributes } 
  end

Bí quyết chính ở đây là khi bạn khai báo initialize_with, factory_girl sẽ không cố gắng gán các thuộc tính cho đối tượng resultant nữa. Nó cũng có vẻ như bỏ qua cửa hàng db trong trường hợp này. Vì vậy, thay vì xây dựng bất cứ thứ gì phức tạp, chúng tôi chỉ trả lại hàm băm thuộc tính đã chuẩn bị sẵn làm nội dung của chúng tôi. Thì đấy.

Dường như cần chỉ định một số giá trị cho lớp, mặc dù nó không thực sự được sử dụng. Điều này là để ngăn factory_girl cố gắng khởi tạo một lớp dựa trên tên nhà máy. Tôi đã chọn sử dụng các lớp mô tả thay vì Đối tượng, nhưng điều đó tùy thuộc vào bạn.

Bạn vẫn có thể ghi đè các trường khi sử dụng một trong các nhà máy băm sau:

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

..however, nếu bạn có nội dung lồng nhau và muốn ghi đè các trường sâu hơn, bạn sẽ cần tăng độ phức tạp của khối khởi tạo để thực hiện một số loại hợp nhất sâu.

Trong trường hợp của bạn, bạn đang sử dụng một số dữ liệu băm và mảng hỗn hợp và có vẻ như thuộc tính Đường dẫn nên được sử dụng lại giữa các phần của cấu trúc dữ liệu. Không sao cả - bạn biết cấu trúc của nội dung, vì vậy bạn có thể dễ dàng tạo một nhà máy xây dựng mảng kết quả đúng cách. Đây là cách tôi có thể làm điều đó:

  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)

Bạn cũng vẫn có thể tự do bỏ qua các giá trị không cần thiết. Hãy tưởng tượng rằng chỉ Path và rev là thực sự cần thiết:

  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)

Đây là một giải pháp tuyệt vời. Nó thậm chí còn hoạt động với sự kế thừa của các nhà máy.
David Pelaez

Điều này phù hợp với tôi để tạo / xây dựng, nhưng nó không thành công: FacoryGirl.lint
pixelearth

Cảm ơn vì điều này. Để vượt qua Rubocop linter trong khối favoritesnhiều dòng, hãy sử dụng do..endthay vì {{..}}.
Scarver 2

bạn có thể thêm skip_createvào nhà máy nếu bạn muốn gọi 'tạo ra' thay vìbuild
Sairam

Tuyệt quá. Tôi thấy tôi có thể khởi tạo bất kỳ lớp tùy chỉnh nào, initialize_withđánh giá trong ngữ cảnh lớp, tức là nếu tôi có initialize_with { new(attributes) }, build :my_factorysẽ trả về kết quả làMyClass.new(attributes)
MikDiet

10

điều này làm việc cho tôi và tôi có thể chuyển các thuộc tính khi cần thiết vào hàm băm

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
Điều này cũng có lợi ích bổ sung là cho phép các phím là chuỗi.
crftr

nhược điểm ở đây là bạn đang sửa đổi một đối tượng duy nhất chứ không phải một đối tượng mới mỗi khi nó được tạo. Hãy xem object_id of the hash's
Anthony


6

Bạn có thể thực hiện việc này trong phiên bản mới nhất của factory_girl, nhưng thật khó xử vì nó được thiết kế để xây dựng các đối tượng chứ không phải cấu trúc dữ liệu. Đây là một ví dụ:

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

Xem qua những thứ kỳ lạ ở đây:

  • Mỗi nhà máy đều cần một lớp xây dựng hợp lệ ngay cả khi nó không được sử dụng, vì vậy tôi đã chuyển Objectđến đây để ngăn nó tìm kiếm DropboxHash.
  • Bạn cần bỏ qua tất cả các thuộc tính bằng cách sử dụng một ignorekhối để sau đó nó không cố gắng gán chúng cho mảng, chẳng hạn như array.revision = 48.
  • Bạn có thể cho nó biết cách kết hợp kết quả của bạn với nhau bằng cách sử dụng initialize_with. Nhược điểm ở đây là bạn cần phải viết lại danh sách thuộc tính đầy đủ.
  • Bạn cần cung cấp một to_createkhối trống để nó không cố gọi array.save!sau đó.

0

Tôi đã sử dụng OpenStruct:

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

Chỉnh sửa: xin lỗi, không hoạt động như một Hash

Cuối cùng tôi sử dụng phiên bản tĩnh, chỉ để giữ cho hàm băm đó đến từ hệ thống Nhà máy ...

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

tìm kiếm thứ gì đó tốt hơn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.