zoukankan      html  css  js  c++  java
  • Rails 5 Test Prescriptions 第6章Adding Data to Tests

    bcreate the data quickly and easily。考虑测试运行的速度。

    fixtures and factories.以及下章讨论的test doubles,还有原生的create创建的,没有一个方案可以解决所有情景。


    Fxitures

    如果想使用固件。RSpec目录是spec/fixtures/projects.yml。 Mini test的目录是test/fixtures/

    runway:
       name: Project Runway

       due_date: 2016-12-18

    projects(:runway) 

    名字可以描述用途,比如projects(:project_with_no_due_date)

    Fixture接受ERB files.可以使用<%= %> ,不建议使用使用循环。

    Loading Fixture Data

    在测试开始时固件会一次性加载,使用事物transaction,因此在测试结束时会回滚。回归初始状态。

    固件运行速度块。固件是全局性的数据 储存在database中。

    固件是分散的,不适合管理connections,关联数据。 

    总之,固件不适合在复杂的程序使用。
     


    Factories   factory_bot 

    gem 'factory_bot_rails'  目录spec/factories/

    在spec的一个文件中配置:

    RSpec.configure do |config|
      config.include FactoryBot::Syntax::Methods
    end

    每次用create方法无需加上FactoryBot前缀了。 

    详细用法:本博客: https://www.cnblogs.com/chentianwei/p/9047596.html

    Factory_bot假定class的名字就是你定义的名字。如果要自定义类,需要指定类名。 

    FactoryBot.define do
      factory :project, class: Project do
        name "Project Runway"
        due_date {Date.today - rand(50)} #随机时间。50天内的。
      end
    end

    Basic Factory Creation

    build(:project): 非关联对象可以使用。

    create(:project):别用,除非对象之间有关联,必须存入数据库。因为会让测试减慢。

    attributes_for(:project)   需要对hash属性进行验证时,使用,一般见于controller test。


    build_stubbed(:project) Unlike build, it assigns a fake ActiveRecord ID to the model and stubs out database-interaction methods (like save) such that the test raises an exception if they are called. 

    Prescription: 尽量使用这个方法,有build的一切功能,还能生成一个假Rails id,有了这个就能建立belongs_to 关联,同时不会被存入数据库。

    *_pair  and *_list 两个方法,没看。 

    Associations and Factories 

    FactoryBot.define do
      factory :task do
        title "Thing to do"
        size 1
        completed_at nil
        project   

      #这样调用task = create(:task)就会自动调用task.project = create(:project)

      end
    end

    也可以单独建立关联:

    task = FactoryBot.create(:task,  project: Project.new) 

    如果已经在factory definition中建立了关联,同时不想在测试中有value,设置nil 

    task = FactoryBot.create(:task, project: nil)

    如果关联名字不匹配factory name或者你想指定关联对象的默认的属性:

    在factory definition 中使用association方法

    association :doer,  factory: :user,  name: "Task Doer"

    只有保存在数据库中,对象有了id才能关联。但可以使用build_stubbed来创建不保存的对象

    或者使用create方法。

    作者建议在定义中建立关联,但不设置属性。属性在测试中设置。

    association :user  

    更直接的 user 

    Managing Duplication in Factories 

    对于2个以上的factories, Factory_bot可以做到管理。文档里面有许多技巧,但以下3个最常用。

     

    sequence方法 

    对于需要unique values 的属性,如登陆,或电子邮件。可以使用sequence方法。

    sequence(:title) { |n| "Task #{n}"

    起始n是1. 每被调用一次n加1。

     

    inherited factories 继承的特性

    FactoryBot.define do
      factory :task do
        sequence(:title){ |n| "Task #{n}"}  
    #可以嵌套进来
        factory :big_task do
          size 5
        end
        factory :small_task do
          size 1
        end
      end
    #或者加上parent: :task
      factory :middle_task, parent: :task do
        size 3
      end
    end

    trait方法 

    trait 

    优点:设置一个有意义的名字,方便理解

    缺点:需要额外的输入和增加了复杂度。 

    用于指定一批的特定的属性,一个省事的方法。

    这个方法放在factory :task的块中,就可以被task使用。 

    FactoryBot.define do
      factory :task do
        title "Thing to do"
        size 1
        completed_at nil
        trait :small do
          size 1
        end

     #继承一个对象,并使用了trait

        factory :trivial do
          small
        end
      end
    end

    调用: let(:task){build(:task, :smal)} 

    Preventing Factory Abuse

    创建最小数量的数据刚好够测试用就可以了。


    Dates and Times 

    测试历法逻辑,让人头疼,但可以使用a couple of things 来简化时间逻辑这个野兽 .

     

    Using Relative Dates 

    Date.today 和 1.day.ago, 2.months.ago, 2.weeks.ago结合使用。

    如在

    factory :project do

      start_date {1.week.ago} 

    end 


    gutenberg:

      start_date: <%= 1.day.ago %> 

    缺点就是如果某个时间是已知的,就没办法使用相对时间了。

    Stubbing Time 

    把时间冻结!!!用a stub来明确指定时间。

    需要用到Raisl helper方法。

    ActiveSupport::Testing::TimeHelpers#travel

    Changes current time to the time in the future or in the past by a given time difference by stubbing Time.nowDate.today, and DateTime.now. The stubs are automatically removed at the end of the test. 

    travel(duration, &block)
    Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
    travel 1.day do
      User.create.created_at # => Sun, 10 Nov 2013 15:34:49 EST -05:00
    end
    Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00

    如 travel 1.month, 接受一段时间作为参数。 一个整数。

    ActiveSupport::Testing::TimeHelpers#travel_to 

    travel_to(date_or_time)

    接受1个固定的时间/日记,作为参数。 

     pasting

    Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
    travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do
      Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
    end
    Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00

    trave_back 重置时间回到初始状态。 

    可以在这两个参数的块内,进行断言,或者期望expect.

    Comparing Time 

    Ruby有三个独立的时间类。Time, Date, DateTime.

    因此Date的实例和DateTime的实例是无法比较和加减的 

    使用to_s(:db)进行转化。

     1.day.ago.to_date.to_s(:db)  => "2018-05-25"
     1.day.ago.to_date   => Fri, 25 May 2018

    Setting Rails Timestamps 

    可以使用created_at 在预制件,或者固件中。 

  • 相关阅读:
    作业6 团队项目之需求(改)
    作业6第一天进度
    作业6第二天进度
    作业6四则运算APP之Sprint计划
    作业6第3、4、5天进度
    重新梳理Python基础(7)
    BAE博客开发之基础知识积累Django篇(1)
    重新梳理Python基础(11)
    重新梳理Python基础(6)
    重新梳理Python基础(9)
  • 原文地址:https://www.cnblogs.com/chentianwei/p/9093901.html
Copyright © 2011-2022 走看看