设置对象以使用factory_girl进行模型测试 [英] setting up objects for model testing with factory_girl

查看:48
本文介绍了设置对象以使用factory_girl进行模型测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想测试以下范围,但不知道如何正确设置测试对象.我什至不知道我是否应该在工厂中创建具有某些关联或使用let/local var的那些.

I'd like to test the scopes below but don't know hot to setup test objects properly. I don't even know if I should create those in factory with some associations or using let/local vars.

task.rb

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

工厂

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

task_spec.rb

task_spec.rb

describe Task do

  .....

  describe "scopes" do

    #I DON'T KNOW HOW TO SETUP THE TEST OBJECTS PROPERLY
    let(:uncompleted_task) { create(:task) }
    let(:completed_task) { create(:task, completed_at: DateTime.now - 2) }
    let(:user) { create(:user) 

    let(:task_1) { create(:task, executor_id: user.id, assigner_id: (user.id + 1)) }
    let(:task_2) { create(:task, assigner_id: user.id, executor_id: (user.id + 1) }
    let(:task_3) { create(:task, assigner_id: user.id, executor_id: (user.id + 2) }

    it "completed" do
      expect(completed_task).to eq(Task.completed.first)
    end

    it "uncompleted" do
      expect(uncompleted_task).to eq(Task.uncompleted.last)
    end

    it "alltasks" do

    end

    it "between" do
    end
  end
end

推荐答案

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

First of all, I prefer NOT to setup associations in factories due to the following reasons:

  1. 如果工厂中存在关联,则每次创建/构建对象时,都会同时创建关联的对象.这意味着即使您只是构建"一个对象,也会触发许多数据库访问.您使用的关联越多,运行测试所需的时间就越多.
  2. 您应该在真正需要的时候在测试中设置关联.如果您在工厂中设置关联,则意味着给定时间"流程的给定"部分将从测试中隐藏.当测试失败时,发现问题出在哪里变得更加困难.

要测试范围,您应遵循一些最佳做法:

To test a scope, you should follow some best practices:

  1. 使作用域尽可能简单,测试复杂的作用域更加困难.例如,如果需要,您应该将between范围分解为较小的范围.
  2. 使用最小对象来测试范围,因为我们需要在数据库中创建记录以测试范围.数据库访问减慢了测试速度,我们应尽可能减少对象的创建.在大多数情况下,两个对象(正数和负数)应该足以测试一个简单的范围.
  1. Make your scopes as simple as possible, it is harder to test complicated scopes. For example, you should break down your between scope to small ones if needed.
  2. Use the minimal objects to test the scope because we need to create records in database to test a scope. The database access slows down the testing and we should reduce the object creation as possible. For most cases, two objects (positive and negative) should be enough to test a simple scope.

顺便说一句,您可能会误解let的用法,用let定义的对象仅在测试用例中被调用时才创建.在您的原始规格中,不会创建任何任务或用户,因为不会调用任何任务或用户.要执行所需的操作,应改用before块.

By the way, you may misunderstand the usage of let, the object defined with let is created only when the object is called in test cases. In your original specs, no tasks or users are created because none of them is called. To do what you want, you should use before block instead.

以您的示例为例,我将在下面创建工厂和规格:

For your example, I would create factories and specs below:

工厂

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构建健康代码库"一书中有更多有关如何编写测试的详细信息和热门信息,如果您有兴趣的话,值得阅读.

There are more details and hits about how to write tests in the book "Rails 4 Test Prescriptions - Build a Healthy Codebase by Noel Rappin", and it is worth reading if you are interested.

这篇关于设置对象以使用factory_girl进行模型测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆