【问题标题】:how to treat dependent objects (not sure how to phrase this)如何处理依赖对象(不知道如何表达)
【发布时间】:2018-03-07 20:16:04
【问题描述】:

我正在学习 TDD 和 Rails。我正在伤害自己的“逻辑”问题。让我先介绍一个情况。

我们有 3 个模型:ProjectMissionAttachment。我是这样创建它们的

rails g model Mission
rails g model Project
rails g model Attachment title:string attachable:references{polymorphic}
rake db:migrate

是什么生成了这个schema.rb

ActiveRecord::Schema.define(version: 20180307200338) do
  create_table "attachments", force: :cascade do |t|
    t.string "attachable_type"
    t.integer "attachable_id"
    t.string "title"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["attachable_type", "attachable_id"], name: "index_attachments_on_attachable_type_and_attachable_id"
  end
  create_table "missions", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
  create_table "projects", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end

对于模型,我们有:

# app/models/mission.rb
class Mission < ApplicationRecord
  has_many :attachments, :as => :attachable
end

# app/models/project.rb
class Project < ApplicationRecord
  has_many :attachments, :as => :attachable
end

# app/models/attachment.rb
class Attachment < ApplicationRecord
  belongs_to :attachable, polymorphic: true
end

现在我们有了上下文,我想介绍一下我的“逻辑”问题。对我来说,像这样创建Attachment 是完全合乎逻辑的:

Mission.find(1).attachments.create(file: 'my-file.jpg')
Project.find(1).attachments.create(file: 'my-file.jpg')

但很难想象自己会创建这样的附件:

Attachment.create(attachable: Mission.find(1))
Attachment.create(attachable: Project.find(1))

在开始 TDD 之前,我从未想过这一点。我总是使用第一种方法,就是这样。但现在我正在为我的 Attachment 模型编写测试,我最终会做以下事情:

require 'test_helper'

class AttachmentTest < ActiveSupport::TestCase

  test "should be valid" do
    resource = build(:attachment)
    assert resource.valid?
  end

  # FIXME is 'attachable' the final name?
  test "should require attachable" do
    resource = build(:attachment, attachable: nil)
    assert resource.invalid?
  end

  test "should require file" do
    resource = build(:attachment, file: nil)
    assert resource.invalid?
  end
end

不知何故,我正在测试永远不会发生的场景build(:attachment)

所以我的问题是:我是否应该辞职去想“我必须这样做才能证明Project.attachments.build() 会起作用”?

我也在测试ProjectMission 之类的东西:

  • 应该有很多附件
  • 应该允许创建附件
  • 应保存附件
  • 应该检索附件

这变得令人困惑。

在测试方面,应该如何测试这种关系?

抱歉,这篇文章很长(可能)有点混乱。

编辑

问题奖励有没有办法简单地说“我们不能从附件创建并且必须通过关系”

【问题讨论】:

  • 是的,但是您应该使您的断言更加明确,因为如果任何其他验证失败,assert resource.invalid? 将给出误报。你想做类似assert_includes "some error message", resource.errors[:some_field] 的事情。反之亦然 - 对于您要测试的有效情况,错误哈希中不存在密钥。
  • 你是否真的需要在这个级别对关联进行单元测试是有争议的。您可以测试连接是否正常工作,这将间接测试它。
  • 是的,但是作为一个单元测试它是毫无价值的,因为它需要很多其他移动部件才能不给出误报/误报。相信我,我以前曾被这个确切的问题所困扰。
  • @DanielCosta 测试不应依赖于订单。但如果你想这样做 => apidock.com/ruby/v1_9_3_392/MiniTest/Unit/TestCase/…
  • 我同意@max 你不应该测试record.valid?。例如,如果您添加一个新列,如 description,并验证其存在性 + 删除 file 上的存在性验证,但您忘记相应地更新工厂,那么您的测试 should require a file 仍然会通过,即使它失败了出于完全不同的原因。如果您使用的是 Rails 5,那么有一个非常简洁的 record.errors.details 可以让您执行 assert_includes record.errors.details[:file], {error: :blank}。我们实际上在 Rails 4 中实现了details,因为它支持非常精确的测试

标签: ruby-on-rails activerecord activemodel ruby-on-rails-5


【解决方案1】:

在我看来,您正在尝试测试 Rails 中内置的功能:

  • 应该有很多附件 = test has_many :attachments
  • 应该允许创建附件 = testaccepts_nested_attributes_for :attachments
  • 应该保存附件 = 测试 autosavehas_many
  • 应该检索附件 = 再次测试has_many :attachments

还有,你自己说的:

不知何故,我正在测试永远不会发生的场景build(:attachment)

那何必呢?


您想测试您的对象以确保它们响应规范。例如,如果你想确保Attachment 必须有 attachable,那么你可以这样写:

test 'must have attachable' do
  attachment = Attachment.new.tap(&:valid?)
  assert_includes(attachment.errors.details[:attachable], { error: :blank })
end

这是,我认为,确保您已对属性进行存在验证的最佳选择。

【讨论】:

  • 所以如果做得好,我不应该测试我是否在项目和任务中拥有很多?而是测试我可以从 attachment-test.rb 中添加附件的事实?
  • 我在你的例子中迷失的地方是我正在测试附件,同时对其进行新的和有效的测试。而且我知道在实际场景中,我总是会通过 projects.attachments.create(file...) 来创建附件
  • attachment_test.rb 测试类应该定义 tests 以确保 Attachment 模型响应您的 specs,例如验证是否存在attachablefile 等。你知道你永远不会做Attachment.create(...),但是你会把“确保可附加是强制性的”测试放在哪里?在has_many :attachable 的模型的每个测试类中?多次测试某些东西似乎有点矫枉过正(IMO)
  • 所以最后你的问题的答案我应该辞职去想“我必须这样做才能证明 Project.attachments.build() 会起作用”? 是的,项目测试类不应该负责测试关联对象的行为。 @DanielCosta
  • 这是有道理的。我明白你说的。我是这种情况,我应该测试有很多关系吗?如果我按照你的逻辑,我只是​​测试它是否响应附件但不测试附件关系的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多