sRails 4.2 / Rspec / rspec-retry - 关联属于/has_many 失败

2024-05-04

我在 rspec 上面临着一个巨大的问题,每次我尝试解决一个错误时,它都会创建另一个错误。

我有一个模型交易,其中有_许多步骤

模型/步骤.rb

  belongs_to :deal,             :foreign_key => 'deal_id'

模型/deal.rb

has_many   :steps,          dependent:  :destroy do
    # added to enable maximum nb of steps a deal can have
    # to take into account in active admin
    # in order to calculate the correct new nb of step to compare to the authorized limit
    # source: homeonrails.com/2012/10/validating-nested-associations-in-rails/
    def length
      reject(&:marked_for_destruction?).length
    end
  end 

我所有错误的要点是如何使我的功能 rspec 测试之一工作,其中我将交易和步骤关联起来。我曾经使用 Factory Girl“通常”瞬态,这会更干净,但我必须放弃它(请参阅下文),因为我们有特殊要求:

factory :deal_with_associated_steps do
          to_create {|instance| instance.save(validate: false) } # skip validate

          transient do
            steps_count 27
          end

          after(:create) do |deal, evaluator|
            create_list(:steps, evaluator.steps_count, deal: deal)

          end
        end

我不再使用这种“瞬态”技术来创建与交易相关的多个步骤的原因与我们的应用程序非常相关。

当您获取给定 Deal 的所有关联 Steps 的 st_appearance_order_nb (整数)时,它必须始终是: - 从0开始 - 然后没有间隙,所以 1, 2,3...

Deal 模型 Deals 上的一些 before_validations 让我能够确保始终如此。您不能与关联步骤进行交易,其中一个步骤的外观_nb 为 1,另一个步骤的外观_nb 为 3,但不存在外观_nb 为 2 的步骤。并且您不能拥有外观_nb 为 2 的步骤。 0. 它必须是一个系列 0,1,2,3...等等

实际上,这仍然适用于在 Factory Girl 中创建 Steps 的“经典瞬态”方式。但是上面创建步骤的经典“瞬态”方式的问题是我有一个称为“rspec-重试”的宝石 https://github.com/NoRedInk/rspec-retry这可以帮助我重新进行功能测试,就像许多其他具有复杂 UI/javascript 页面的 rspec 用户一样,有时我的前端测试第一次会因为某些 js/加载原因而失败,然后如果您重复足够多的次数,则第二次或第三次它会起作用的。所以我的大多数功能测试都运行了 4 次,有些只通过了第二次或第三次:) gem rspec-retry 很简洁,但与我在 Factory Girl 中创建相关步骤的“瞬态”方式有一个非常重大的问题:

我收到错误,因为如果测试第一次“重试”失败,第二次,就像测试应用程序认为 st_appearance_order_nb nb 0 到 4 已经被采用(实际上它们是由第一个 rspec“尝试”创建的),所以现在它创建了 4 个新步骤,st_appearance_order_nb 分别为 5、6、7 和 8。

然后...导致错误,因为我有一个 before_validation 来确保交易相关步骤的 st_appearance_order_nb 始终从 0 开始,然后一一递增

因此,使用 rspec-retry,我无法使用 Factory Girl 瞬态方式创建关联的步骤,至少这是我当时找到另一种方法时的结论:我决定以这种方式“手动”创建关联的步骤

let!(:deal_with_videos)   { create(:deal, 
                                    title:  "title deal 1" ) }

video_urls  = [ "", # no video allowed on first step
                  "https://www.facebook.com/418234631906607/videos/495053617558041", # square video (5 sec)
                  "https://www.facebook.com/pili.morillo.56/videos/352355988613922", # landscape video with internal black sidebars
                  "https://www.facebook.com/rihanna/videos/10155330511896676/", # landscape video no internal black sidebars
                  "https://www.facebook.com/videos/1592424637461205/", # portrait video
                  "" 
                ]

(0..5).each do |n|
    let!(:"deal_with_videos_step#{n}") {
      FactoryGirl.create(:step,
        st_appearance_order_nb: n,        
        st_video_url: video_urls[n],
        deal: deal_with_videos)
    }
  end

这修复了错误,我的 99% 的测试都有效,但现在这篇文章的问题是:我的一个测试失败了:因为非常奇怪的是,我关联 Deal 和 Steps 的方式并不完全地工作,但只是部分......让我补充一下,在生产和开发模式下一切都工作正常。

describe "on Deal Page load, the view behaves appropriately in terms of  video" do        
            let(:action)                    { visit actual_deal_page_path(deal_with_videos) }
            let(:fb_player_visibility)      { "hidden" }
            let(:video_href_set_by_app_js)  { nil.to_s }            
            it_behaves_like "a view where the FB video player behaves appropriately"To be clear I found a very hack way to do stuff, but it created another issue in a ripple effect a new bug as the way I was doing it was making the test suite think there was no new

测试失败的原因我现在知道:它失败了因为下面的 before_validation 的内容永远不会被执行

models/deal.rb
    before_validation :extract_st_embed_hostings_from_st_video_urls
    def extract_st_embed_hostings_from_st_video_urls
            puts "beacon1"
            self.steps.reject(&:marked_for_destruction?).each do |step| 
                puts "beacon2" 
    # do stuff                      
            end
        end

我知道,因为这是测试环境中带有这些 put 消息的问题,当我在测试块上运行 rspec test 时,我只看到“beacon1”,而不是 beacon2 (在 dev 和 prod 中都看到这两条消息)

我想知道为什么它没有被执行。

所以我在测试中添加了一些puts看看为什么这条线self.steps.reject(&:marked_for_destruction?).each do |step|没有输出任何东西。我的交易和步骤关联在测试中是否不起作用?

  describe "on Deal Page load, the iew behaves appropriately in terms of  video" do
        before do
          action
          puts deal_with_videos.steps.to_json
          puts deal_with_videos.steps[1].to_json
          puts deal_with_videos.id 
          puts deal_with_videos_step0.deal_id 
          puts deal_with_videos_step0.deal.title
          puts deal_with_videos_step0.to_json
        end

        let(:action)                    { visit actual_deal_page_path(deal_with_videos) }
        let(:fb_player_visibility)      { "hidden" }

        it_behaves_like "a view where the FB video player behaves appropriately"
      end

结果很奇怪:

  • “puts deal_with_videos.steps.to_json”给了我 [] => 所以看来它们没有关联

    • “放置 deal_with_videos.steps1 https://github.com/NoRedInk/rspec-retry.to_json”给出“null”,与前面的一致puts

    • 但 netx 2 带来了更多混乱:

    “puts deal_with_videos.id”给出 3

    “puts deal_with_videos_step0.deal_id”也给我 3

因此,在两个方向上,我得到了相同的信息,这很奇怪:看起来它们实际上是密切相关的。很奇怪,因为它对我来说与前两个看跌期权相矛盾。

  • 但最后的“看跌期权”给了我:

放置 deal_with_videos_step0.deal.title 给中小企业“标题 deal1”

put deal_with_videos_step0.to_json 为我提供了一个详细的 json,其中包含内容(为了保持简洁,此处未复制) => 他们都工作

我的结论

就像我将它们联系起来的方式只有一种方式: 如果我从像 deal_with_videos_step0 这样的步骤开始,然后使用 .deal 移动到 Deal 表,它就会起作用。

但反过来说,我的 before_validation 中名为 extract_st_embed_hostings_from_st_video_urls (见上文)的那个无法正常工作,它无法正常工作:如果我从交易表开始,然后请求与交易相关的所有步骤,则它不起作用,它给了我空输出。所以下面的请求是空的,这就是为什么验证前 extract_st_embed_hostings_from_st_video_urls 不执行任何操作,测试套件认为没有步骤可以执行操作。

所以我被困在这里:我的问题是在工厂女孩+rspec-重试+我的特定交易模型的关联步骤属性约束的十字路口

如何在我的测试中关联一个交易和多个步骤,同时使用 rspec-retry 并设法使该测试通过,也就是说,通过设法让 self.steps.reject(&:marked_for_destruction?).each “work”即使在测试环境中,也不会认为没有相关的“步骤”?

EDIT

以下评论提供了更多信息

1/ st_appearance_order_nb

  • 创建

st_appearance_order_nb 只是步骤的一个属性/列。 Ut已添加到Active Admin中直接在交易表单内通过 has_many 关系:

f.inputs "Steps" do
      f.has_many :steps,
                   allow_destroy: true,
                   heading:       false, 
                   new_record:    true,
                   # ensure each new step is automagically assigned a +1st_appearance_order_nb
                   sortable:      :st_appearance_order_nb,
                   sortable_start: 0 do |step|
        step.input :st_appearance_order_nb,
          input_html: { readonly: true, disabled: true },
          label:      "Appearance rank"  
        step.input :st_video_url,       

      end
    end 
  • 添加/删除的完整性...

模型/deal.rb

before_validation :assign_new_st_appearance_order_nb_values_for_steps_in_case_of_steps_removals     
before_validation :check_steps_start_on_zero 
before_validation :check_steps_have_no_gap_for_st_appearance_order_nb

# in case one or more Steps are removed, avoid a "hole"
# in the st_appearance_order_nb due to those removals
# includes the other requirement to re-start the ranks at 0
    def assign_new_st_appearance_order_nb_values_for_steps_in_case_of_steps_removals
      if self.steps.any? && self.steps.select { |st| st.marked_for_destruction? }.any? # restrict this taxing operation to cases where there are removals
        remaining_steps = self.steps.reject(&:marked_for_destruction?)        
        remaining_steps.sort_by(&:st_appearance_order_nb).each_with_index do |step, index|
          step.update_attributes st_appearance_order_nb: index
        end
      end
    end 

    def check_steps_start_on_zero
      if self.steps.any?
        if self.steps.map{|u| u.st_appearance_order_nb}.min != 0
          errors[:base] << "Error on Steps. There must be at least one Step with Appearance rank equal to 0 ."
        end
      end
    end

    def check_steps_have_no_gap_for_st_appearance_order_nb
      if self.steps.any?
        if !array_one_steps_increment?( self.steps.map{|u| u.st_appearance_order_nb} )
          errors[:base] << "Error on Steps: you can't have gaps inside the list of Appearance ranks. Only increments by one. Change the Appearance ranks accordindly."
        end
      end
    end 
    def array_one_steps_increment?(array)
      sorted = array.sort
      lastNum = sorted[0]
      sorted[1, sorted.count].each do |n|
        if lastNum + 1 != n
          return false
        end
        lastNum = n
      end
      true
    end

EDIT

经过几天的搜索没有成功,有点放弃,但以一种有意义的方式:确实,也许如此多的困难来自于我在功能规范中测试这一点,实际上我不应该让应用程序回调“自行设置”(通过 set 方法)那些有问题的属性(例如 st_embed_hosting),所以我选择在功能测试中自己模拟它们,并进行实际测试以查看回调是否在模型规范中工作。希望它会更加一致和有效。


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

sRails 4.2 / Rspec / rspec-retry - 关联属于/has_many 失败 的相关文章

  • (Rails) Assert_Select 的烦人警告

    有谁知道如何让assert select在rake测试期间不输出所有那些讨厌的html警告 你知道 就像这样的东西 ignoring attempt to close body with div opened at byte 1036 li
  • Rails/Nginx 中的超时——最佳实践

    我正在开发一个应该在 Nginx 服务器上运行的 Rails 应用程序 根据输入 应用程序可能需要很长时间来处理请求 或者在出现错误时挂起 因此我想防止进程永远运行 除了确保客户端收到超时信号的 Nginx 配置之外 我想我可能仍然需要确保
  • 浏览器关闭时 Omniauth 会话过期

    在我的 Rails 3 应用程序中 我使用 Omniauth 进行用户身份验证部分 fb twitter 实际上我遵循这个 https github com RailsApps rails3 mongoid omniauth https g
  • Rails:named_scope、lambda 和块

    我认为以下两个是等效的 named scope admin lambda company id conditions gt company id company id named scope admin lambda do company
  • 使用 Ruby aws-sdk 跟踪文件到 S3 的上传进度

    首先 我知道SO中有很多与此类似的问题 在过去的一周里 我读了大部分 如果不是全部 但我仍然无法让这项工作为我工作 我正在开发一个 Ruby on Rails 应用程序 允许用户将 mp3 文件上传到 Amazon S3 上传本身工作正常
  • 即使在急切加载之后,belongs_to 关联也会单独加载

    我有以下关联 class Picture lt ActiveRecord Base belongs to user end class User lt ActiveRecord Base has many pictures end 在我的
  • Rails - 渲染:目标锚标记的操作?

    我希望像这样使用渲染 render action gt page form 我也尝试过这个 render template gt site page form 那也没用 这个特定页面上的表单位于最底部 如果提交时发生任何错误 我不希望用户被
  • Rails 4 应用程序...在开发环境中,除非刷新页面,否则 javascript 不会触发

    所以我的第一个rails4应用程序遇到了一个奇怪的问题 除非我重新加载页面 否则我的页面javascript不会触发 对于我的 asset pipeline JS 和 content for JS 来说都是如此 在我的 assets jav
  • Bundle 说 gem 丢失了 - 但事实并非如此?

    背景 我正在维护contentRuby On Rails 站点 但我确实没有 Rails 的经验 当尝试运行 Rails 服务器时 rails s我明白了 在任何来源中均找不到 activesupport 3 2 0 Run bundle
  • 来自控制器的 Rails 验证

    有一个联系页面 可以输入姓名 电话 电子邮件和消息 然后发送到管理员的电子邮件 没有理由将消息存储在数据库中 问题 如何 在控制器中使用 Rails 验证 根本不使用模型 或者 在模型中使用验证 但没有任何数据库关系 UPD Model c
  • Ruby/Rails 集合到集合

    我有两个表与一个连接表连接 这只是伪代码 Library Book LibraryBooks 我需要做的是 如果我有一个图书馆的 id 我想获取该图书馆拥有的所有书籍所在的所有图书馆 因此 如果我有图书馆 1 图书馆 1 中有书籍 A 和
  • 资产管道:仅对一个控制器使用 javascript 文件

    在 Ruby on Rails v4 中 我希望仅为特定控制器加载一个 js 文件 或一组 js 文件 执行此操作的标准方法是什么 在 application js 中有 require tree 线 我假设这需要删除 所以我并不总是加载每
  • 从父应用程序重新打开 Rails 3 引擎类

    就目前而言 您无法重新打开引擎中包含的引擎类 app只需在父应用程序的目录中添加相同的类即可 app目录 例如 my engine app controllers users controller rb my app app control
  • 我想要一个默认选择空白值的日期选择框

    我用了以下date select助手 但没有一个显示默认情况下选择空白值的日期选择框 通过以下所有代码 我得到了选择框 但选择了当前日期 我在 Rails 2 3 2 上
  • 使用rSpec 测试delayed_job 链的最佳方法是什么?

    目前 当我的代码中有一个延迟方法时 如下所示 CommentMailer delay deliver comments comment true 我在规范中写了这样的内容 dj mock DelayProxy CommentMailer s
  • 带有 OAuth2 的 YouTube API v3:更新和删除失败并出现“权限不足”错误

    我在尝试着update and delete视频使用YouTube API v3 https developers google com youtube v3 docs videos with OAuth2 用于身份验证 https dev
  • Rails 资源单数还是复数?

    我有一条搜索路线 我想将其设为单数 但是当我指定单数路线时 它仍然会生成复数控制器路线 这是应该的样子吗 resource search Gives me search POST search format action gt create
  • Rails 4:将数据库导出到 YAML

    使用 Rails 2 3 可以使用几个插件之一将数据库轻松导出 转储 到 YAML 请参阅将数据库表导出到 YAML 文件的最佳方法 https stackoverflow com questions 490507 best way to
  • Rails 安全:完全避免大规模分配

    我倾向于不需要批量分配 http guides rubyonrails org security html mass assignment我的生产代码中的功能 在我的测试代码中 我经常使用它 但在这些情况下我do想要设置任意列 因此 如果在
  • 正则表达式的 o 修饰符是什么意思?

    Ruby 正则表达式有一些选项 例如i x m o i例如 意味着忽略大小写 什么是o选项是什么意思 在ri Regexp 它说o意味着执行 仅插值一次 但是当我这样做时 a one b a a two b不改变 它保持 one 我缺少什么

随机推荐