我正在使用Laravel 5.2应用程序。我正在尝试使用SQLite内存数据库设置测试。
我了解与更改[{1}}列而不指定默认值相关的SQLite问题(例如described in this question)。一个明显的解决方法是使该字段首先为空,然后在单独的事务中立即撤消该字段。因此,我花了很多时间来处理所有迁移并执行以下操作:
NOT NULL
我也知道SQLite问题,每个事务不能超过1列(例如described here)。我花了很多时间来更新我的迁移来做到这一点。
现在所有迁移都使用SQLite成功运行并回滚而没有错误:memory:;它们在MySQL中运行良好。
所以我使用迁移添加了一个测试。测试所做的第一件也是唯一的事就是使用工厂来创建客户:
Schema::table('customers', function (Blueprint $table) {
$table->string('first', 128)->after('id')->nullable();
});
Schema::table('customers', function (Blueprint $table) {
$table->string('first', 128)->after('id')->nullable(false)->change();
});
创建客户后查询的输出显示它工作正常(虚假数据来自Faker):
<?php
namespace Tests\Unit;
use TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class PromoTest extends TestCase
{
use DatabaseMigrations;
/** @test */
public function dummy_test() {
factory('App\Customer')->create();
print_r(\DB::select('select * from customers'));
}
}
但是在输出之后,测试立即崩溃并抛出以下错误:
SQLSTATE [23000]:完整性约束违规:19 NOT NULL约束失败:customers.name(SQL:INSERT INTO客户(id,email,zipcode,subscribe,created_at,updated_at,name)SELECT id,email,zipcode,subscribe ,created_at,updated_at,name FROM __temp__customers)
请注意,导致问题的$ ./vendor/bin/phpunit --filter PromoTest
PHPUnit 4.8.24 by Sebastian Bergmann and contributors.
EArray
(
[0] => stdClass Object
(
[id] => 1
[email] => nRyan@example.net
[zipcode] => 47049-6020
[subscribe] => 0
[created_at] => 2017-08-25 15:47:28
[updated_at] => 2017-08-25 15:47:28
[first] => Syble
[last] => Hahn
[phone] => (761)073-7794x8624
[invalid_email] =>
)
)
字段不会出现在上面创建的记录中。此表中的name
字段过去确实存在,但不再存在 - 我将其删除(使用迁移),现在使用name
和first
。显然,迁移是有效的,因为创建,插入和转出的记录具有正确的当前字段。
那么为什么Laravel在已经成功创建当前记录的记录之后尝试将记录插入到旧版本的表中?
我只是猜测,但看起来在测试完成后,并且正在回滚迁移,数据被保存并复制或重新插入到模式的每个历史迭代中?虽然没有办法可以工作......?
有没有人见过这个?是预料还是我做错了什么?
UPDATE 如果我只是转而使用MySQL进行测试,问题就会消失。看起来我现在必须这样做,因为我很难过。我更喜欢在内存中使用SQLite,因为它更快。