【问题标题】:Unit testing Postgresql PHP PDO fails单元测试 Postgresql PHP PDO 失败
【发布时间】:2013-07-13 21:12:28
【问题描述】:

我一直在编写自己的 PHP 模型系统,它提供基本的 ORM 和 DBAL 支持,仅作为学习课程。它让我可以编写我以前从未做过的事情,并使用我从未使用过的 SQLite 和 PostgreSQL 等数据库。

模型包:https://github.com/titon/Model PgSQL包:https://github.com/titon/Model.PostgreSQL

我遇到的问题是对 PgSQL 驱动程序进行单元测试(我有 MySQL 和 SQLite 工作)。每次运行单元测试时,我都会收到以下错误:

PDOException : SQLSTATE[55000]: Object not in prerequisite state: 7 ERROR:  currval of sequence "users_id_seq" is not yet defined in this session

我知道这个问题是什么,但我似乎没有解决它。它甚至没有达到我的单元测试,它在夹具设置部分失败。以下是每个单元测试期间采取的步骤:

  1. 驱动程序在setUp()期间初始化并连接
  2. 单元测试方法被调用
  3. 夹具已加载
    1. CREATE TABLE 语句被调用
    2. 调用 CREATE INDEX 语句
    3. INSERT 记录被调用
  4. 已运行单元测试
  5. 调用tearDown() 卸载固定装置(DROP TABLE 和 INDEX)并断开驱动程序

在步骤 3.3 插入夹具记录时发生错误。它插入第一条记录(共 10 条),但尝试获取最后一条插入 ID 失败(上面的序列错误)。当我检查 PGAdmin 时,表和序列确实存在,所以我很困惑。

  • 在调用插入时序列是否尚未完全创建?
  • 我的连接会话是否过早终止?
  • 我该如何解决这个问题?

我对 PgSQL 非常陌生,因此我们将不胜感激。作为记录,代码使用 PHP PDO 并调用 lastInsertId('table_column_seq') 来检索最后一个 ID。

如果您有兴趣,这里是夹具设置 SQL。

CREATE TABLE IF NOT EXISTS "users" (
    "id" serial NOT NULL,
    "country_id" integer NULL DEFAULT NULL,
    "username" varchar(255) NULL,
    "password" varchar(255) NULL,
    "email" varchar(255) NULL,
    "firstName" varchar(255) NULL,
    "lastName" varchar(255) NULL,
    "age" smallint NULL,
    "created" timestamp NULL DEFAULT NULL,
    "modified" timestamp NULL DEFAULT NULL,
    UNIQUE ("username")
);
CREATE INDEX "country_id" ON "users" ("country_id");
INSERT INTO "users" ("id", "country_id", "username", "firstName", "lastName", "password", "email", "age", "created") VALUES ('1', 1, 'miles', 'Miles', 'Johnson', '1Z5895jf72yL77h', 'miles@email.com', 25, '1988-02-26 21:22:34');
# Fails right after this insert

【问题讨论】:

  • 如果要使用序列(SERIAL 数据类型),为什么要在 INSERT 语句中传递文字 ID?为什么要将该文字作为字符串而不是整数传递?为什么没有主键?为什么用户名是唯一的,但可以为空?
  • 固定装置基本上是简单的数据,带有随机模式和类型,其中一些在文字 prod 设置中没有意义。固定装置也在 MySQL、PgSQL、SQLite 和 MongoDB 之间共享,因此有一些怪癖可以让一切正常工作。此外,语句输出也不是完全匹配,因为 PDO 语句无法与其绑定值一起看到。这些只是自动生成的。

标签: php unit-testing postgresql pdo


【解决方案1】:

不要猜测,知道。打开语句记录,看看它做了什么。

然后您可能会看到 lastInserId() 调用正在从 id 上的序列中获取最后一个 id。没有一个,因为您提供了自己的价值。停止这样做,它应该可以工作。

【讨论】:

  • 啊,如此简单的疏忽。固定装置用于 MySQL、SQLite、PgSQL 和 MongoDB,因此 ID 是硬编码的。如果我需要连接关系记录,您建议如何编写单元测试?
  • 如果您不在数据库中生成 ID,为什么要获取 last-insert-id 呢?我不太明白这有什么意义。如果您确实需要知道刚刚提供给数据库的值,您当然可以通过 INSERT 上的 RETURNING 子句返回 ID。
  • 好吧,我插入了硬编码的夹具记录,但是很多单元测试会插入更多行或删除,因此对 ID 进行硬编码更容易。但假设我删除了他们都应该以正确顺序插入的 ID。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-09
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-27
相关资源
最近更新 更多