【发布时间】:2018-03-07 20:16:04
【问题描述】:
我正在学习 TDD 和 Rails。我正在伤害自己的“逻辑”问题。让我先介绍一个情况。
我们有 3 个模型:Project、Mission、Attachment。我是这样创建它们的
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() 会起作用”?
我也在测试Project 和Mission 之类的东西:
- 应该有很多附件
- 应该允许创建附件
- 应保存附件
- 应该检索附件
这变得令人困惑。
在测试方面,应该如何测试这种关系?
抱歉,这篇文章很长(可能)有点混乱。
编辑
问题奖励有没有办法简单地说“我们不能从附件创建并且必须通过关系”
【问题讨论】:
-
是的,但是您应该使您的断言更加明确,因为如果任何其他验证失败,
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