Ruby on rails 分析Mongoid事件生成的ActiveRecord对象时,Rspec测试随机失败

Ruby on rails 分析Mongoid事件生成的ActiveRecord对象时,Rspec测试随机失败,ruby-on-rails,mongodb,activerecord,rspec,Ruby On Rails,Mongodb,Activerecord,Rspec,我实现了一个基于Mongoid的活动日志机制,它将事件保存在MongoDB中 Mongoid模型Activity具有after\u创建事件,根据记录的活动类型执行不同的任务:(简化示例) 测试如下所示: it 'should hide previous [objects] create a new updated one' do 2.times do user.log_activity(:user_did_something) end i

我实现了一个基于Mongoid的活动日志机制,它将事件保存在MongoDB中

Mongoid模型
Activity
具有
after\u创建
事件,根据记录的活动类型执行不同的任务:(简化示例)

测试如下所示:

 it 'should hide previous [objects] create a new updated one' do
      2.times do 
        user.log_activity(:user_did_something) 
      end
      items = MyItems.where(:type => :user_did_something)
      items.count.should == 2
    end
 end
let(:items_count) { MyItems.where(:type => :user_did_something).count }

it 'should hide previous [objects] create a new updated one' do
  expect { 2.times { user.log_activity(:user_did_something) } }.
  to change { items_count }.from(0).to(2)
end
有时,对
项的测试失败。计数
为0而不是2。
仅当从命令行运行时才会发生这种情况
rspec spec

仅运行此测试或使用Guard运行所有测试时,不会发生这种情况。

假设问题在于测试设置(而不是代码)中的某些竞争条件,我建议使用rspec,它应该等待在DB中创建对象,然后再对其进行计数:

 it 'should hide previous [objects] create a new updated one' do
  items = MyItems.where(:type => :user_did_something)

  expect { 2.times { user.log_activity(:user_did_something) } }.
  to change { items.count }.from(0).to(2)
end

[编辑] 为了使测试总体上更干净(虽然这不会影响行为,但我不认为),您还可以使用rspec的延迟加载
let
,如下所示:

 it 'should hide previous [objects] create a new updated one' do
      2.times do 
        user.log_activity(:user_did_something) 
      end
      items = MyItems.where(:type => :user_did_something)
      items.count.should == 2
    end
 end
let(:items_count) { MyItems.where(:type => :user_did_something).count }

it 'should hide previous [objects] create a new updated one' do
  expect { 2.times { user.log_activity(:user_did_something) } }.
  to change { items_count }.from(0).to(2)
end

在典型的Mongodb设置中,数据库写入成功返回和数据读取之间可能存在延迟。原因有两个:

  • 为了提高性能,在将数据提交到磁盘之前,可能会返回“不安全”写入
  • Mongodb使用副本集,存在复制延迟。通常,读取作为负载平衡的一种形式分发到副本,因此即使使用安全写入,也可能是从与刚写入的服务器不同的服务器读取,因此看不到刚写入的数据

为了确保始终能够立即读回刚刚使用Mongoid编写的数据,需要设置数据库会话选项
一致性::strong,安全性:true
,这两个选项都不是默认选项

对于单元测试,您的测试涵盖了很多内容:

  • 调用创建
  • 回调后的
    
    
  • 在用户做了某件事之后调用
  • 已创建
    MyItem
    对象
  • 我建议您将其分解为几个单元测试,每个单元测试一件事情。你从中得到的附加值是,至少,你会知道测试的哪个部分实际上失败了

    class Activity
      include Mongoid::Document
    
      after_create { |activity| my_after_create_callback(activity.event_type) }
    
      def my_after_create_callback(activity_type)
        method_name = "after_#{activity_type}"
        send(method_name) if respond_to? method_name
      end
    
      def after_user_did_something
        MyItem.create!(:type => :user_did_something)
      end
    end
    


    您能否提供
    log\u活动
    code?当您说“设置数据库会话选项”时,我们如何在
    config/mongoid.yml
    Rails应用程序中做到这一点?这些密钥需要在
    config/mongoid.yml
    文件的哪个父密钥中设置?