使用factory_girl设置模型测试对象

时间:2016-04-13 22:19:56

标签: ruby-on-rails rspec factory-bot

我想测试下面的示波器,但不知道如何正确设置测试对象。我甚至不知道我是否应该在工厂中创建一些关联或使用let / local vars。

task.rb

static Drawable recolorDrawable(Drawable icon, int toColor)
{
    Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas myCanvas = new Canvas(bitmap);

    icon.setColorFilter(toColor, PorterDuff.Mode.SRC_IN);
    icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
    icon.draw(myCanvas);

    return new BitmapDrawable(context.getResources(), bitmap);
}

工厂

belongs_to :assigner, class_name: "User"
belongs_to :executor, class_name: "User"

scope :completed, -> { where.not(completed_at: nil) }
scope :uncompleted, -> { where(completed_at: nil) }
scope :alltasks, -> (u) { where('executor_id = ? OR assigner_id = ?', u.id, u.id) }
scope :between, -> (assigner_id, executor_id) do
  where("(tasks.assigner_id = ? AND tasks.executor_id = ?) OR (tasks.assigner_id = ? AND tasks.executor_id = ?)", assigner_id, executor_id, executor_id, assigner_id)
end

task_spec.rb

factory :task do
  content { Faker::Lorem.sentence }
  deadline { Faker::Time.between(DateTime.now + 2, DateTime.now + 3) }
  association :executor, factory: :user
  association :assigner, factory: :user #I guess this is not right
end

factory :user do
  sequence(:email) { |n| "example#{n}@gmail.com" }
  password 'example0000'
  password_confirmation 'example0000'
  new_chat_notification { Faker::Number.between(0, 10) }
  new_other_notification { Faker::Number.between(0, 10) } 
end

1 个答案:

答案 0 :(得分:2)

首先,由于以下原因,我不想在工厂中设置关联:

  1. 如果工厂中存在关联,则每次创建/构建对象时,都会同时创建关联对象。这意味着即使您只是“构建”一个对象,也会触发许多数据库访问。您使用的关联越多,运行测试所需的时间就越多。
  2. 您应该在真正需要时设置测试中的关联。如果在工厂中设置关联,则意味着在测试时隐藏了给定时间进程的“给定”部分。当测试失败时,找到出错的地方变得更加困难。
  3. 要测试范围,您应该遵循一些最佳做法:

    1. 使示波器尽可能简单,测试复杂的示波器更难。例如,如果需要,您应该将between范围细分为小范围。
    2. 使用最小对象来测试范围,因为我们需要在数据库中创建记录来测试范围。数据库访问会减慢测试速度,我们应该尽可能减少对象的创建。对于大多数情况,两个对象(正面和负面)应该足以测试一个简单的范围。
    3. 顺便说一下,您可能会误解let的用法,只有在测试用例中调用对象时才会创建用let定义的对象。在原始规范中,不会创建任何任务或用户,因为它们都不会被调用。要做你想做的事,你应该使用before阻止。

      对于您的示例,我将在下面创建工厂和规范:

      工厂

      factory :task do
        content { Faker::Lorem.sentence }
        deadline { Faker::Time.between(DateTime.now + 2, DateTime.now + 3) }
      end
      
      factory :user do
        sequence(:email) { |n| "example#{n}@gmail.com" }
        sequence(:password) { |n| "password#{n}" }
        password_confirmation { password }
        new_chat_notification { Faker::Number.between(0, 10) }
        new_other_notification { Faker::Number.between(0, 10) }
      end
      

      功能

      describe Task do
        # ...
        describe "scopes" do
          let(:executor) { create(:user) }
          let(:assigner) { create(:user) }
      
          describe "completeness related" do
            before(:example) do
              @uncompleted_task = create(:task, executor: executor, assigner: assigner)
              @completed_task = create(:task, executor: executor, assigner: assigner, completed_at: DateTime.now - 2))
            end
      
            it "completed" do
              expect(Task.completed).to include(@completed_task)
              expect(Task.completed).not_to include(@uncompleted_task)
            end
      
            it "uncompleted" do
              expect(Task.uncompleted).to include(@uncompleted_task)
              expect(Task.uncompleted).not_to include(@completed_task)
            end
          end
      
          it "alltasks" do
            me = create(:user)
            owned_task = create(:task, executor: me, assigner: assigner)
            assigned_task = create(:task, executor: executor, assigner: me)
            not_my_task = create(:task, executor: executor, assigner: assigner)
            expect(Task.alltasks(me)).to include(owned_task, assigned_task)
            expect(Task.alltasks(me)).not_to include(not_my_task)
          end
      
          it "between" do
            # ... (there should be as last 5 tasks to create)...
          end
        end
        # ...
      end
      

      关于如何在“Rails 4测试处方 - 由Noel Rappin建立一个健康的代码库”一书中编写测试的更多细节和点击,如果您感兴趣,值得一读。