Rails:minitest 是否使用 schema.rb 重新创建测试模式?

Rails: does minitest use schema.rb to recreate the test schema?

我正在尝试将遗留的 Rails 系统提升到更新的标准,但是在让测试数据库反映 schema.rb plus 的状态时遇到问题通过迁移进行的更改。

tl;dr 运行ning rake minitest:all 是否调用与 rake db:schema:load 相同的代码?

环境

原始系统状态

该系统最初是由非软件工程师、不了解 Rails 等的人设置的。添加了几个 MySQL 特定类型(例如 unsigned int ) 没有特别支持使用 Rails' 迁移和 schema.rb。所以系统使用了 structure.sql 并且对于如何保持更新、签入 git 等等非常草率。

此外,在后来的某个时候,有人决定 替换 一些常用的数字、自动递增主键 id 字段为 varchar包含一个自生成的 GUID。字段名称仍然是 id 但它是一种新的数据类型。

但是所有数百个测试(他们 确实 编写了很多测试)都被编写为基于 ids 引用 fixture 实例,而不是 fixture 名称,并且它们之间存在依赖关系fixtures 等。他们没有更新测试,而是决定坚持使用旧模式(使用数字 id)进行测试,并使用新模式(使用 id 中的 varchar GUID)进行生产。

OP深吸一口气...

各种环境的数据库不同步,有数百次迁移,但它们停止工作,因为 "development" 数据库是共享的,而且......你知道,这是一团糟。

我正在尝试解决所有这些问题,并最终迁移到 PostgreSQL。

我做了什么

我使用 RAILS_ENV=production rake db:structure:dump 从本地生产数据库转储了模式——这产生了一个权威的 structure.sql。我创建了一个新的开发数据库,​​并使用 rake db:structure:load 加载了它的模式——我仔细比较了生产和开发模式,它们是相同的,甚至是我上面提到的 MySQL-specific unsigned int。

出于两个原因,我想改用 schema.rb。首先,我想获得一个不依赖于 MySQL 的系统。其次,当使用 structure.sql 时,我们检查一个文件,该文件具有自动增量值、数据库设置和任何机器的其他特征 运行 最近的 db:migrate。这会产生我希望避免的问题。

因此,我在本地将配置设置从 :sql 更改为使用 :ruby 设置来生成 schema.rb

但是 schema.rb 真的不喜欢将 id 字段变成 varchar 的想法 -- 我已经确保所有使用此声明的模型 self.primary_key = :id,然后我创建了一个新的迁移来替换所有旧的,"rollup migration",其内容主要是新的 schema.rb,但在几个方面进行了修改。

特别是,id 字段是 GUID varchar 我这样设置 table(从迁移中):

class RolledUpStateAsOf20150403 < ActiveRecord::Migration

  def up

    # ... all other table definitions in the system

    create_table "users", :id => false, :force => false do |t|
      t.string   "id", :limit => 36, :default => "", :null => false
      t.string   "login"
      # and all the other user fields
    end
    execute("ALTER TABLE users ADD PRIMARY KEY (id);")

    #...
  end

  def down
    raise ActiveRecord::IrreversibleMigration
  end
end

所以:

以后每次我创建一个新的迁移时,schema.rb 都会更新——目前还不准确(直到我们稍后摆脱那些古怪的 id 字段) .迁移将遵循正常的 Rails 做法向前推进。

一旦生产、登台、开发和其他数据库同步,那么一切都很好。

除了我们测试的时候。

那么,为什么在我 运行 Minitest 时这不起作用?

我运行正在使用 minitest 进行如下测试:

RAILS_ENV=test rake db:drop
RAILS_ENV=test rake db:create
RAILS_ENV=test rake db:migrate
RAILS_ENV=test rake minitest:all

但后来我开始看到错误,这些错误是由于 id 列被定义为 int 而不是 varchar

如果我在 运行ning minitest 之前检查模式 (在 dropcreate 和我的魔法迁移之后),它是正确:根据需要,时髦的主键是 varchar

但在测试过程中的某个地方,架构似乎正在改回 Rails 标准。我可以返回并检查 ID 列返回 int 的架构。

大概是根据实际 schema.rb.

生成架构

这是normal/expected行为吗?关于如何实现我的目标的任何建议,很简单:

  • 迁移再次起作用
  • 开发、测试、登台、生产数据库在结构上是相同的
  • 我现在需要忍受疯狂的 varchar 基于 GUID id 的字段
  • 如果可能,我更喜欢不使用structure.sql

好的,所以我相信以下内容是正确的:minitest,或测试 do 运行 db:schema:load ... 或 db:structure:load当 运行ning 在 RAILS_ENV=test 时——这可以通过 运行ning rake test --tracerake minitest:all --trace.

观察到

所以,因为我的 schema.rb 不会完全重新创建数据库,因为对名为 id 的字段奇怪地使用 varchar 而不是 int...我不得不改用 structure.sql

解决方案的其余部分,包括将 schema.rb 的手动修改版本添加为第一个 "rollup" 迁移效果很好,后续迁移也很好。将来某个时候,我会把这些 id 变回它们的自然形态;目前,这是一个合适的解决方案,即使不够优雅。