使用 RSpec 在 Rails 中的序列化对象中测试顺序

问题描述

我正在尝试测试请求规范中索引操作的序列化对象的顺序。控制器索引操作具有以下代码

def index
  user_platforms = current_user.user_platforms.order('created_at desc')

  render json: UserPlatformsSerializer.new(user_platforms),status: :ok
end

通常当我测试序列化对象作为响应时:

# request spec
let(:user) { create(:user) }
let(:user_platforms) { create_list(:user_platform,5,user: user)

it 'return user platforms in response' do
  expect(JSON.parse(response.body)).to eq(UserPlatformsSerializer.new(user_platforms).serializable_hash.as_json)
end

但是因为我需要按照特定的顺序,所以我需要在断言之前准备期望值,所以我的尝试是:

it 'return ordered user platforms with created_at in the response' do
  expected = UserPlatformsSerializer.new(user_platforms)
    .serializable_hash.as_json['data']
    .sort_by { |h| h['attributes']['created_at'] }.reverse

  expect(JSON.parse(response.body)['data']).to eq expected
end

这工作正常并且测试通过了,但以这种方式编写测试似乎不直观。 这个测试的另一个问题是它依赖于序列化对象中 created_at 属性的存在,在我的情况下我不需要它,我将它添加到序列化程序只是为了让测试通过。

有没有更好的方法来测试序列化对象中的顺序?

我正在使用 jsonapi-serializer gem。

解决方法

我会这样做:

let(:user_platforms) do
  [
    create(:user_platform)],create(:user_platform,created_at: Time.current - 5.minutes)
  ] 
}
end

以所需的顺序向规范中的序列化程序提供对象。

,

通常,当我需要测试散列中项目的顺序时,我只是比较期望值/以 JSON 字符串形式给出,因为如果顺序不同,则比较将失败:

expect(response.body))
.to eq(JSON.dump(UserPlatformsSerializer.new(user_platforms).serializable_hash))

维护起来有点困难,因为这样更难看出差异,但它不依赖于任何时间戳。

,

我认为您不需要在序列化程序上传递 created_at 属性,因为他只用于对您的查询进行排序。

不如创建一个“随机”用户列表,您可以更改您创建的每个用户的 created_at 字段:

let(:user1) { create(:user,created_at: Time.current) }
let(:user2) { create(:user,created_at: Time.current - 5.minutes) }
let(:user3) { create(:user,created_at: Time.current + 5.minutes) }

这样,您就已经知道您想要的预期顺序了。因此,您只需要检查您的 response.body 是否为 eq,订单 [user3,user1,user2]