首页 > 解决方案 > 在 minitest 中测试 postgres“RANDOM()”

问题描述

介绍

我的 RoR 项目中有一个层次结构父子,我为我们的 ruby​​ on rails 项目编写了一个新功能,它显示了来自父项的两个随机子记录。

class Article < ActiveRecord::Base
  has_many :reviews

  def to_json
    {
      ...
      reviews: reviews.n_random.as_json
      ...
    }
  end
end

class Review < ActiveRecord::Base
  belongs_to :article

  scope :n_random, ->(n=2) { order("RANDOM()").limit(n) }
end

现在,我遇到的问题是即使随机性正常工作,即使在测试中,我也遇到了一些实际间接测试此功能的测试的问题。

假设我有一个ArticlesControllerTest测试套件,其中包含一个方法

test 'show renders correct article' do
    # given
  params = { format: :json, id: 1 } 
  article = Article.find(params[:id])

    # when
  post :get, params
  response_article = JSON.parse(response.body, symbolize_names: true)


    #then
  assert_response 200
  assert_equal response_article, article.to_json
end

问题

最后一个assert_equal失败,因为例如:

问题

是否可以编写某种过滤器,使 postgres 的RANDOM()返回值始终为常量?我知道我可以SELECT setseed(0.5);用来设置种子,以便下一个SELECT RANDOM();返回相同的值(尽管下一个RANDOM()会改变),但我想要实现的是setseed(0.5)在从活动记录中进行每个可能的选择之前做一些事情。

我很乐意接受任何其他可以帮助我解决这个问题的回复,因为我知道 RoR 和 Postgres 是两个不同的服务器,我不知道如何从 postgres 方面测试这种随机性。

inb4:我不想大幅度修改测试。

标签: ruby-on-railspostgresqlrandompsqlminitest

解决方案


您可能应该为此使用模拟/存根,以确保仅在此测试范围内具有一致的值。例如,使用Mocha

Article.any_instance.stubs(:to_json).returns({
  ...
  reviews: reviews.last(2).as_json,
  ...
})

或者

Review.expects(:n_random).returns(Review.last(2))

而且,在本例中,您可以使用以下方法撤销这些:

Article.any_instance.unstub(:to_json)

注意我不确定:n_random类上存根的语法,因为我没有测试它的环境,但希望你能明白(来源在这里)。

这意味着,在您的测试中,您将看到一致的数据,覆盖RANDOM()排序。这样您就可以测试您的控制器是否正在执行预期的操作,而不必担心在测试环境之外使用的随机数据。

要实施,只需在您的测试中包含上述之一,即

test 'show renders correct article' do
  Review.expects(:n_random).returns(Review.last(2))

  # given
  params = { format: :json, id: 1 } 
  article = Article.find(params[:id])

  # when
  post :get, params
  response_article = JSON.parse(response.body, symbolize_names: true)


  #then
  assert_response 200
  assert_equal response_article, article.to_json
end

推荐阅读