在 minitest 中测试 postgres "RANDOM()"
Testing postgres "RANDOM()" in minitest
简介
我的 RoR 项目中有层次结构 parent-children
我在 rails 项目上为我们的 ruby 写了一个新功能,它显示了来自 parent.
的两个随机 children 记录
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
失败了,因为例如:
response_article
包含 ID 1, 2
article.to_json
包含 ID 1, 3
问题
是否可以编写某种过滤器,使 postgres 的 RANDOM()
return 始终保持恒定值?我知道我可以使用 SELECT setseed(0.5);
设置种子,以便下一个 SELECT RANDOM();
return 具有相同的值(尽管下一个 RANDOM()
会改变),但我想要什么要实现的是在活动记录中的每个可能 select 之前做类似 setseed(0.5)
的事情。
我很乐意接受任何其他有助于我解决这个问题的回复,因为我知道 RoR 和 Postgres 是两个不同的服务器,我不知道如何从 postgres 端测试这种随机性。
inb4:我不想大量修改测试。
你应该使用 mocks / stubs for this, ensuring a consistent value just for the scope of this test. For example, with 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.B。我不确定 class 上的 :n_random
存根的语法,因为我没有测试它的环境,但希望你明白了 (source here)。
这意味着,在您的测试中,您将看到一致的数据,覆盖 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
简介
我的 RoR 项目中有层次结构 parent-children 我在 rails 项目上为我们的 ruby 写了一个新功能,它显示了来自 parent.
的两个随机 children 记录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
失败了,因为例如:
response_article
包含 ID1, 2
article.to_json
包含 ID1, 3
问题
是否可以编写某种过滤器,使 postgres 的 RANDOM()
return 始终保持恒定值?我知道我可以使用 SELECT setseed(0.5);
设置种子,以便下一个 SELECT RANDOM();
return 具有相同的值(尽管下一个 RANDOM()
会改变),但我想要什么要实现的是在活动记录中的每个可能 select 之前做类似 setseed(0.5)
的事情。
我很乐意接受任何其他有助于我解决这个问题的回复,因为我知道 RoR 和 Postgres 是两个不同的服务器,我不知道如何从 postgres 端测试这种随机性。
inb4:我不想大量修改测试。
你应该使用 mocks / stubs for this, ensuring a consistent value just for the scope of this test. For example, with 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.B。我不确定 class 上的 :n_random
存根的语法,因为我没有测试它的环境,但希望你明白了 (source here)。
这意味着,在您的测试中,您将看到一致的数据,覆盖 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