【问题标题】:RSpec proper way to check created columnRSpec检查创建列的正确方法
【发布时间】:2020-07-19 23:32:46
【问题描述】:

我有 POST 端点,它在我的数据库中创建一个新的 JourneyProgress 记录。

    post :enroll do
      JourneyProgress.create!(user: current_user, journey: journey, percent_progress: 0.0, started_at: DateTime.now)
      status :no_content
    end

我想检查percent_progressstarted_at 是否通过以下示例设置:

  let(:current_date) { 'Thu, 16 Jul 2020 17:08:02 +0200'.to_date }

  before do
    allow(DateTime).to receive(:now) { current_date }
  end

    it 'set starting progress' do
      call
      expect(JourneyProgress.last.started_at).to eq(current_date)
      expect(JourneyProgress.last.percent_progress).to eq(0.0)
    end

规范会通过,但我不确定JourneyProgress.last.(some record name) 是否符合惯例。有没有更好的方法来检查这个?

如果我将其更改为:

it 'set starting progress' do
  expect(call.started_at).to eq(current_date)
  ...
end

我收到一个错误:

 NoMethodError:
   undefined method `started_at' for 204:Integer

【问题讨论】:

  • 您的端点返回status :no_content (HTTP 204),这就是您在第二次使用时收到错误的原因。因此,如果您关心检查新记录的值,则需要照常查找(或简单地检查 JourneyProgress 记录的计数是否增加了 1)。
  • 正确的状态码应该是 201 Created 并且要么包含一个带有新创建资源的位置标头,要么包含一个包含该资源的 JSON 响应正文。在这种情况下,204 响应对客户端毫无用处。
  • 我会说最好检查 HTTP 响应,但这种方法也可以。

标签: ruby-on-rails ruby rspec


【解决方案1】:

如果您真的想测试started_at 列的值,类似这样的方法会起作用。

it 'set starting progress' do
  call
  expect(JourneyProgress.last.started_at).to eq(current_date)
end

但我建议您对在这种情况下值得测试的内容三思而后行,检查 JourneyProgress 记录是否已插入您的数据库以及端点是否实际返回正确会更有意义HTTP 状态码。

  it 'persists the record in database' do
    expect { call }.to change { JourneyProgress.count }.by(1)
  end

  it 'responds with no content status' do
    call
    expect(response).to have_http_status(:no_content)
  end   

正如其他 cmets 所说,我也会使用 201 (created) 而不是在这种情况下不使用任何内容。

【讨论】:

  • 你真的需要测试 ActiveRecord 吗?
  • @aridlehoover 不仅仅是测试 ActiveRecord,您正在测试您的端点是否将某些内容持久化到数据库中,因此如果将来有人错误地将 .create 部分更改为其他内容,测试就会中断。跨度>
  • 不知何故,我错过了这是一个控制器测试的事实。无论如何,继续访问数据库。这就是 Rails 的方式。
【解决方案2】:

您似乎正在尝试编写一个集成测试,以验证您的软件是否将一条记录写入数据库,其中 percent_progress 和 started_at 的值是适当的。

您担心在您的测试中使用.last 是正确的。如果您要在构建服务器上并行运行测试,很有可能两个不同的测试都会同时(或以不确定的顺序)将记录添加到数据库中,从而导致测试不稳定。您可以通过返回新创建记录的 id 并在调用事件之后在测试中查找该记录来解决这种潜在的不稳定。但是,有一个更好的解决方案...

如果您要将 JourneyProgress 模型的迁移修改为如下所示:

create_table :journey_progress do |t|
  t.user_id :integer
  t.journey_id :integer
  t.percent_progress :float, default: 0.0

  t.timestamps
end

然后,您可以保证percent_progress 字段始终默认为0.0。而且,您可以使用 ActiveRecord 管理的 created_at 时间戳来代替您必须管理的自定义 started_at 时间戳。

因此,您不必测试任何一项设置是否正确,因为您可以相信 ActiveRecord 和您的数据库会做正确的事情,因为它们的作者已经对它们进行了彻底的测试。

现在,您的代码看起来更像这样:

post :enroll do
  journey_progress = JourneyProgress.create!(
    user: current_user, 
    journey: journey
  )

  status :created
end

而且,您的测试看起来更像 Sebastian Delgado 提到的:

it 'persists the record in database' do
  expect { call }.to change { JourneyProgress.count }.by(1)
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 2015-03-12
    • 2014-12-10
    • 1970-01-01
    相关资源
    最近更新 更多