Mongoid block until created?

2019-08-16 00:03发布

问题:

I'm creating tests for an API with rspec using Mongoid and FactoryGirl. Mongoid is not a problem in production, but when testing API specs like so:

it "renders [person]" do
  person = FactoryGirl.create(:person)
  get 'persons'
  json.count.should eq(1)
end

the model instance being created (in this case Person) is sometimes not reflected in the database by the time the API call runs, resulting in an error like so:

 Failure/Error: json.count.should eq(1)

   expected: 1
        got: 0

   (compared using ==)

How can I create new database entries and block further execution of the spec until I know that the entry is reflected in the database?

回答1:

As stated in this answer:

To ensure that you can always immediately read back the data you just wrote using Mongoid, you need to set the database session options

consistency: :strong, safe: true

neither of which are the default.



回答2:

you can use Fabrications instead of factory girl... which is much better/ more stable/ can do all sorts of models... for example i had this problem...

and here is another example

if you plan to fabricate a model with a certain conditions like ( a subscribed user can only create a review ) the following fabrication can do it

Fabricator(:review) do
  rating         { (1..5).to_a.sample }
  content        { Faker::Lorem.sentence(2) }
  subscription   { Fabricate(:subscription) } # review this subscription
  author         { Fabricate(:user) } # author of the review
  before_create do |review|
    # this insures that the author had already subscribed to the subscription
    # so that the review model doesn't throw validation errors.
    subscription.subscribers.create!(user: author)
  end
end

and this is something you cannot ever do with FactoryGirl...

bottom line i've used FactoryGirl for 2 months and I had many problems specially with embedded documents... and i've moved to Fabrications and didn't have a problem with it for over than 4 months... in fact it really helped a lot with the integration tests.



回答3:

As I explained here, Mongoid with Mongodb defaults to an "eventual consistency" model because it provides much higher performance.

In a typical Mongodb setup, there can be a delay between when a database write returns successfully and when that data can be read. There are two reasons for this:

  • For performance gains, an "unsafe" write can return before the data is committed to the disk.
  • Mongodb uses replica sets and there is a replication delay. Commonly reads are distributed to the replicas as a form of load balancing, so even if you use a safe write, you may be reading from a different server than the one you just wrote to and thus not see the data you just wrote.

To ensure that you can always immediately read back the data you just wrote using Mongoid, you need to set the database session options consistency: :strong, safe: true, neither of which are the default.



回答4:

in your mongoid.yml change the config for test env like this:

test:
  sessions:
    default:
      hosts:
        - localhost
      database: project-test
  options:
      ...
      consistency: :strong
      safe: true
      ...

This way mongoid will wait until mongodb finish the operations.



标签: rspec mongoid